Skip to content

Commit

Permalink
Fixes #22529 - Refactor Template rendering to use a proper rendering …
Browse files Browse the repository at this point in the history
…service (#5683)
  • Loading branch information
kamils-iRonin authored and ares committed Jul 27, 2018
1 parent 416eba8 commit f715a7c
Show file tree
Hide file tree
Showing 62 changed files with 1,383 additions and 1,025 deletions.
3 changes: 1 addition & 2 deletions app/controllers/api/v2/config_templates_controller.rb
Expand Up @@ -2,7 +2,6 @@ module Api
module V2
class ConfigTemplatesController < V2::BaseController
include Api::Version2
include Foreman::Renderer
include Foreman::Controller::ProvisioningTemplates
include Foreman::Controller::Parameters::ProvisioningTemplate

Expand Down Expand Up @@ -84,7 +83,7 @@ def destroy

def build_pxe_default
Foreman::Deprecation.api_deprecation_warning("GET method for build pxe default is deprecated. Please use POST instead") if request.method == "GET"
status, msg = ProvisioningTemplate.authorized(:deploy_provisioning_templates).build_pxe_default(self)
status, msg = ProvisioningTemplate.authorized(:deploy_provisioning_templates).build_pxe_default
render_message(msg, :status => status)
end

Expand Down
2 changes: 1 addition & 1 deletion app/controllers/api/v2/hosts_controller.rb
Expand Up @@ -313,7 +313,7 @@ def template
if template.nil?
not_found(_("No template with kind %{kind} for %{host}") % {:kind => params[:kind], :host => @host.to_label})
else
render :json => { :template => @host.render_template(template) }, :status => :ok
render :json => { :template => @host.render_template(template: template) }, :status => :ok
end
end

Expand Down
3 changes: 1 addition & 2 deletions app/controllers/api/v2/provisioning_templates_controller.rb
Expand Up @@ -2,7 +2,6 @@ module Api
module V2
class ProvisioningTemplatesController < V2::BaseController
include Api::Version2
include Foreman::Renderer
include Foreman::Controller::ProvisioningTemplates
include Foreman::Controller::Parameters::ProvisioningTemplate
include Foreman::Controller::TemplateImport
Expand Down Expand Up @@ -95,7 +94,7 @@ def destroy
api :POST, "/provisioning_templates/build_pxe_default", N_("Update the default PXE menu on all configured TFTP servers")

def build_pxe_default
status, msg = ProvisioningTemplate.authorized(:deploy_provisioning_templates).build_pxe_default(self)
status, msg = ProvisioningTemplate.authorized(:deploy_provisioning_templates).build_pxe_default
render_message(msg, :status => status)
end

Expand Down
2 changes: 1 addition & 1 deletion app/controllers/provisioning_templates_controller.rb
Expand Up @@ -3,7 +3,7 @@ class ProvisioningTemplatesController < TemplatesController
helper_method :documentation_anchor

def build_pxe_default
status, msg = ProvisioningTemplate.authorized(:deploy_provisioning_templates).build_pxe_default(self)
status, msg = ProvisioningTemplate.authorized(:deploy_provisioning_templates).build_pxe_default
(status == :ok) ? success(msg) : error(msg)
redirect_back(fallback_location: provisioning_templates_path)
end
Expand Down
6 changes: 2 additions & 4 deletions app/controllers/templates_controller.rb
@@ -1,5 +1,4 @@
class TemplatesController < ApplicationController
include UnattendedHelper # includes also Foreman::Renderer
include Foreman::Controller::ProvisioningTemplates
include Foreman::Controller::AutoCompleteSearch
include AuditsHelper
Expand Down Expand Up @@ -111,11 +110,10 @@ def resource_name
private

def safe_render(template)
load_template_vars
render :plain => unattended_render(template)
render :plain => @host.render_template(template: template, params: params)
rescue => error
Foreman::Logging.exception("Error rendering the #{template.name} template", error)
if error.is_a?(Foreman::Renderer::RenderingError)
if error.is_a?(Foreman::Renderer::Errors::RenderingError)
text = error.message
else
text = _("There was an error rendering the %{name} template: %{error}") % {:name => template.name, :error => error.message}
Expand Down
34 changes: 9 additions & 25 deletions app/controllers/unattended_controller.rb
@@ -1,6 +1,4 @@
class UnattendedController < ApplicationController
include Foreman::Renderer

layout false

# We dont require any of these methods for provisioning
Expand All @@ -15,8 +13,6 @@ class UnattendedController < ApplicationController
before_action :get_built_host_details, :only => [:built, :failed]
before_action :allowed_to_install?, :except => :hostgroup_template
before_action :handle_realm, :if => Proc.new { params[:kind] == 'provision' }
# load "helper" variables to be available in the templates
before_action :load_template_vars, :only => :host_template
# all of our requests should be returned in text/plain
after_action :set_content_type

Expand Down Expand Up @@ -48,8 +44,7 @@ def hostgroup_template
@host = Hostgroup.find_by_title(params['hostgroup'].to_s)
return head(:not_found) unless template && @host

load_template_vars if template.template_kind.name == 'provision'
safe_render template.template
safe_render(template)
end

# Generate an action for each template kind
Expand Down Expand Up @@ -82,8 +77,9 @@ def render_template(type)
# Compatibility with older URLs
type = 'iPXE' if type == 'gPXE'

if (config = @host.provisioning_template({ :kind => type }))
safe_render config
template = @host.provisioning_template({ :kind => type })
if template
safe_render(template)
else
error_message = N_("unable to find %{type} template for %{host} running %{os}")
render_custom_error(:not_found, error_message, {:type => type, :host => @host.name, :os => @host.operatingsystem})
Expand Down Expand Up @@ -246,22 +242,10 @@ def ip_from_request_env
end

def safe_render(template)
if template.is_a?(String)
@unsafe_template_content = template
@template_name = 'Unnamed'
elsif template.is_a?(ProvisioningTemplate)
@unsafe_template_content = template.template
@template_name = template.name
else
raise "unknown template"
end

begin
render :inline => "<%= unattended_render(@unsafe_template_content, @template_name).html_safe %>"
rescue => error
msg = _("There was an error rendering the %s template: ") % @template_name
Foreman::Logging.exception(msg, error)
render :plain => msg + error.message, :status => :internal_server_error
end
render :plain => @host.render_template(template: template, params: params).html_safe
rescue StandardError => error
msg = _("There was an error rendering the %s template: ") % template.name
Foreman::Logging.exception(msg, error)
render :plain => msg + error.message, :status => :internal_server_error
end
end
4 changes: 2 additions & 2 deletions app/helpers/templates_helper.rb
Expand Up @@ -31,11 +31,11 @@ def safemode_methods
end

def safemode_helpers
@@safemode_helpers ||= Foreman::Renderer::ALLOWED_HELPERS.sort.join(' ')
@@safemode_helpers ||= Foreman::Renderer.config.allowed_helpers.sort.join(' ')
end

def safemode_variables
@@safemode_variables ||= Foreman::Renderer::ALLOWED_VARIABLES.sort.map{|x| "@#{x}"}.join(' ')
@@safemode_variables ||= Foreman::Renderer.config.allowed_variables.sort.map{|x| "@#{x}"}.join(' ')
end

def locked_warning(template)
Expand Down
2 changes: 0 additions & 2 deletions app/helpers/unattended_helper.rb
@@ -1,6 +1,4 @@
module UnattendedHelper
include Foreman::Renderer

def ks_console
(@port && @baud) ? "console=ttyS#{@port},#{@baud}" : ""
end
Expand Down
2 changes: 1 addition & 1 deletion app/models/concerns/orchestration/compute.rb
Expand Up @@ -103,7 +103,7 @@ def setUserData
return false
end

self.compute_attributes[:user_data] = unattended_render(template.template)
self.compute_attributes[:user_data] = render_template(template: template)

return false if errors.any?
logger.info "Revoked old certificates and enabled autosign for UserData"
Expand Down
5 changes: 2 additions & 3 deletions app/models/concerns/orchestration/ssh_provision.rb
Expand Up @@ -32,10 +32,9 @@ def queue_ssh_provision_update

def setSSHProvisionScript
logger.info "About to start post launch script on #{name}"
template = provisioning_template(:kind => "finish")
@host = self
template = provisioning_template(:kind => "finish")
logger.info "generating template to upload to #{name}"
self.template_file = unattended_render_to_temp_file(template)
self.template_file = Foreman::Renderer.render_template_to_tempfile(template: template, prefix: id.to_s, host: self)
end

def delSSHProvisionScript
Expand Down
24 changes: 4 additions & 20 deletions app/models/concerns/orchestration/tftp.rb
Expand Up @@ -54,22 +54,6 @@ def rebuild_tftp_kind_safe(kind)
end

def generate_pxe_template(kind)
# this is the only place we generate a template not via a web request
# therefore some workaround is required to "render" the template.
@kernel = host.operatingsystem.kernel(host_medium_provider)
@initrd = host.operatingsystem.initrd(host_medium_provider)
if host.operatingsystem.respond_to?(:mediumpath)
@mediapath = host.operatingsystem.mediumpath(host_medium_provider)
end

# Xen requires additional boot files.
if host.operatingsystem.respond_to?(:xen)
@xen = host.operatingsystem.xen(host_medium_provider)
end

# work around for ensuring that people can use @host as well, as tftp templates were usually confusing.
@host = self.host

return build_pxe_render(kind) if build?
default_pxe_render(kind)
end
Expand All @@ -79,17 +63,17 @@ def generate_pxe_template(kind)
def build_pxe_render(kind)
template = host.provisioning_template({:kind => kind})
return unless template.present?
unattended_render template
host.render_template(template: template)
rescue => e
failure _("Unable to render %{kind} template '%{name}': %{e}") % { :kind => kind, :name => template.try(:name), :e => e }, e
end

def default_pxe_render(kind)
template = ProvisioningTemplate.find_by_name(local_boot_template_name(kind))
raise Foreman::Exception.new(N_("Template '%s' was not found"), template_name) unless template
unattended_render template, template_name
raise Foreman::Exception.new(N_("Template '%s' was not found"), template.name) unless template
host.render_template(template: template)
rescue => e
failure _("Unable to render '%{name}' template: %{e}") % { :name => template_name, :e => e }, e
failure _("Unable to render '%{name}' template: %{e}") % { :name => template.name, :e => e }, e
end

# Adds the host to the forward and reverse TFTP zones
Expand Down
6 changes: 6 additions & 0 deletions app/models/host/base.rb
Expand Up @@ -347,6 +347,12 @@ def orchestrated?
self.class.included_modules.include?(Orchestration)
end

def render_template(template: nil, params: {}, variables: {})
source = Foreman::Renderer.get_source(template: template, host: self)
scope = Foreman::Renderer.get_scope(host: self, params: params, variables: variables)
Foreman::Renderer.render(source, scope)
end

private

def build_values_for_primary_interface!(values_for_primary_interface, args)
Expand Down
28 changes: 11 additions & 17 deletions app/models/host/managed.rb
Expand Up @@ -207,7 +207,6 @@ class Jail < ::Safemode::Jail

if SETTINGS[:unattended]
# handles all orchestration of smart proxies.
include UnattendedHelper # which also includes Foreman::Renderer
include Orchestration
# DHCP orchestration delegation
delegate :dhcp?, :dhcp_records, :to => :primary_interface
Expand Down Expand Up @@ -333,20 +332,21 @@ def handle_realm
end
end

def disk_layout_template
if disk.present?
{ name: 'Custom disk layout', template: disk }
elsif ptable.present?
{ name: ptable.name, template: ptable.layout }
end
def disk_layout_source
@disk_layout_source ||= if disk.present?
Foreman::Renderer::Source::String.new(name: 'Custom disk layout',
content: disk.tr("\r", ''))
elsif ptable.present?
Foreman::Renderer::Source::String.new(name: ptable.name,
content: ptable.layout.tr("\r", ''))
end
end

# returns the host correct disk layout, custom or common
def diskLayout
raise Foreman::Renderer::RenderingError, 'Neither disk nor partition table defined for host' unless disk_layout_template
@host = self
load_template_vars
unattended_render(disk_layout_template[:template].tr("\r", ''), disk_layout_template[:name])
raise Foreman::Renderer::Errors::RenderingError, 'Neither disk nor partition table defined for host' unless disk_layout_source
scope = Foreman::Renderer.get_scope(host: self)
Foreman::Renderer.render(disk_layout_source, scope)
end

# reports methods
Expand Down Expand Up @@ -725,12 +725,6 @@ def validate_media?
managed && pxe_build? && build?
end

def render_template(template)
@host = self
load_template_vars
unattended_render(template)
end

def build_status_checker
build_status = HostBuildStatus.new(self)
build_status.check_all_statuses
Expand Down
19 changes: 13 additions & 6 deletions app/models/hostgroup.rb
Expand Up @@ -113,15 +113,16 @@ def self.title_name
"title".freeze
end

def disk_layout_template
if ptable.present?
{ name: ptable.name, template: ptable.layout }
end
def disk_layout_source
@disk_layout_source ||= if ptable.present?
Foreman::Renderer::Source::String.new(name: ptable.name,
content: ptable.layout.tr("\r", ''))
end
end

def diskLayout
raise Foreman::Renderer::RenderingError, 'Partition table not defined for hostgroup' unless disk_layout_template
disk_layout_template[:template].tr("\r", '')
raise Foreman::Renderer::Errors::RenderingError, 'Partition table not defined for hostgroup' unless disk_layout_source
disk_layout_source.content
end

def all_config_groups
Expand Down Expand Up @@ -244,6 +245,12 @@ def recreate_hosts_config(only = nil, children_hosts = false)
result
end

def render_template(template: nil, params: {}, variables: {})
source = Foreman::Renderer.get_source(template: template, host: self)
scope = Foreman::Renderer.get_scope(host: self, params: params, variables: variables)
Foreman::Renderer.render(source, scope)
end

protected

def lookup_value_match
Expand Down
1 change: 0 additions & 1 deletion app/models/nic/managed.rb
Expand Up @@ -8,7 +8,6 @@ class Managed < Interface
include InterfaceCloning

include Exportable
include Foreman::Renderer

before_validation :set_provisioning_flag
after_save :update_lookup_value_fqdn_matchers, :drop_host_cache
Expand Down
17 changes: 11 additions & 6 deletions app/models/provisioning_template.rb
Expand Up @@ -71,6 +71,12 @@ def used_taxonomy_ids(type)

scope :of_kind, ->(kind) { joins(:template_kind).where("template_kinds.name" => kind) }

def render_template(host: nil, params: {}, variables: {})
source = Foreman::Renderer.get_source(template: self, host: host)
scope = Foreman::Renderer.get_scope(host: host, params: params, variables: variables)
Foreman::Renderer.render(source, scope)
end

def self.template_ids_for(hosts)
hosts = hosts.with_os.distinct
oses = hosts.pluck(:operatingsystem_id)
Expand Down Expand Up @@ -138,27 +144,26 @@ def self.global_default_name(kind)
"#{kind} global default"
end

def self.global_template_name_for(kind, renderer)
def self.global_template_name_for(kind)
global_setting = Setting.find_by(:name => "global_#{kind}")
return global_setting.value if global_setting && global_setting.value.present?
global_template_name = global_default_name(kind)
renderer.logger.info "Could not find user defined global template from Settings for #{kind}, falling back to #{global_template_name}"
Rails.logger.info "Could not find user defined global template from Settings for #{kind}, falling back to #{global_template_name}"
global_template_name
end

def self.build_pxe_default(renderer)
def self.build_pxe_default
return [:unprocessable_entity, _("No TFTP proxies defined, can't continue")] if (proxies = SmartProxy.with_features("TFTP")).empty?
error_msgs = []
used_templates = []
TemplateKind::PXE.each do |kind|
global_template_name = global_template_name_for(kind, renderer)
global_template_name = global_template_name_for(kind)
if (default_template = find_global_default_template global_template_name, kind).nil?
error_msgs << _("Could not find a Configuration Template with the name \"%s\", please create one.") % global_template_name
else
begin
@profiles = pxe_default_combos
allowed_helpers = Foreman::Renderer::ALLOWED_GENERIC_HELPERS + [ :default_template_url ]
menu = renderer.render_safe(default_template.template, allowed_helpers, :profiles => @profiles)
menu = default_template.render_template(variables: { profiles: @profiles })
rescue => exception
Foreman::Logging.exception("Cannot render '#{global_template_name}'", exception)
error_msgs << "#{exception.message} (#{kind})"
Expand Down

0 comments on commit f715a7c

Please sign in to comment.