How to include a subtemplate in a puppet template using future parser - templates

During our upgrade up from Puppet 3.5.7 and after piecing together information from:
How to include a subtemplate in a Puppet template
I could reference a subtemplate with some variable in the filename like so:
<%= scope.function_template([File.dirname(__FILE__) + "/" + "subtemplate_" + #oscar_package + ".properties.erb"]) %>
After enabling the future parser I get the following error:
Error: Could not retrieve catalog from remote server: Error 400 on
SERVER: Evaluation Error: Error while evaluating a Function Call,
Failed to parse template
oscar_mysql_tomcat/context/oscar_demo15.properties.e rb:
Filepath: org/jruby/RubyString.java
Line: 1172
Detail: can't convert nil into String
at /etc/puppet/environments/development/modules/oscar_mysql_tomcat/manifests/context.pp:11:18
on node bcmdit-devel-536-puppetclient Warning: Not using cache on
failed catalog Error: Could not retrieve catalog; skipping run
It is failing at the resolution of #oscar_package, how do I do it the future parser way?
Update 1
After consulting:
https://puppet.com/docs/puppet/5.4/lang_template_erb.html#calling-puppet-functions-from-templates
It seems that I should be using scope.call_function:
<%= scope.call_function('template', [File.dirname(__FILE__) + "/" + "subtemplate_" + #oscar_package + ".properties.erb"]) %>
This yields the same error.

The class I am using is a child of another class with the oscar_package variable defined.
It was solved by passing the variable to the subclass so it could be accessed directly within the scope from where the function in the erb template was called.
So in the init.pp definition the relevant code is:
if $sys_report::active_database_context_list != "" {
oscar_mysql_tomcat::context { "active_${sys_report::active_database_context_list}":
db_name => "$sys_report::active_database_context_list",
oscar_package => "$oscar_package",
oscar_package_build => "$oscar_package_build",
role => "link",
tomcat_site_seal => "$tomcat_site_seal",
tomcat_host_fqdn => "$tomcat_host_fqdn",
tomcat_port => "$tomcat_port",
twitter_feed => "$twitter_feed",
require => File['/etc/sys-report.var'],
}
}

Related

how to pass 2 data bag variables to template chef

I am trying to pass 2 data bags as variables into a template but it end in error message. Do anyone know how do i pass 2 databags to a template?
Recipe
db = data_bag_item('dbconnect', 'connection')
dbkey = data_bag_item('database', 'databasename')
template '/etc/config.cnf' do
source 'config.cnf.erb'
action :create
variables (
:dbcon => db,
:dbk => dbkey
)
end
Template
connection = mysql://<%= #dbcon['dbuser'] %>:<%= #dbcon['dbpasswd'] %>#<%= #dbcon['dbname'] %>/<%= #dbk['dbname'] %>
Okay. I got the answer.
I missed {} brackets in variables.
db = data_bag_item('dbconnect', 'connection')
dbkey = data_bag_item('database', 'databasename')
template '/etc/config.cnf' do
source 'config.cnf.erb'
action :create
variables ({
:dbcon => db,
:dbk => dbkey
})
end

puppet matching multiple agent hostnames to params.pp data structure

I have a module called appserver in my puppet modules.
In that module manifests I have a params.pp file which is inherited by init.pp file.
In params.pp file I have the following data structure.
$servers = {
appserver-mgr => { axis2 => {subDomain => 'mgt',},
carbon => {subDomain => 'mgt',},
serverOptions => '-Dsetup',
server_home => $carbon_home, },
appserver-wkr => { axis2 => {subDomain => 'worker', members => ['appserver-mgr2-ip']},
carbon => {subDomain => 'worker',},
serverOptions => '-DworkerNode=true',
server_home => $carbon_home, },
}
In my init.pp file I'm filling my templates as follows using the said data structure.
define fill_templates($axis2, $carbon, $clustering, $serverOptions, $server_home) {
$ipAdd = $::ipaddress
$hostName = $::hostname
if $hostName == "${name}" {
notify {"host name match found for $hostName for $ipAdd":}
file { "${server_home}/repository/conf/axis2/axis2.xml":
ensure => file,
content => template('appserver/axis2.xml.erb'),
}
->
file { "${server_home}/repository/conf/carbon.xml":
ensure => file,
content => template('appserver/carbon.xml.erb'),
}
->
file { "${server_home}/repository/conf/tomcat/catalina-server.xml":
ensure => file,
content => template('appserver/catalina-server.xml.erb'),
}
}
}
As per the current method, if a matching node is found (say appserver-mgr) the respective data structure values are retrieved and applied to the templates.
Currently these scripts are working as expected.
Now I want to change it as follows.
I have a cluster containing following nodes.
appserver-mgr-1
appserver-mgr-2
appserver-mgr-3
appserver-wkr-1
appserver-wkr-2
appserver-wkr-3
appserver-wkr-4
appserver-wkr-5
By using the same data structure in params.pp file, how can I apply the appserver-mgr configuration to *.mgr nodes 1-3 and appserver-wkr configuration to *.wkr nodes 1-5?
Can I use regular expressions for this task?
I'm quite sure that it would be possible to bend the Puppet DSL to do what you need here. However, the far better approach to this issue is Hiera.
node /appserver-mgr/ {
$node_class = 'appserver'
$node_subclass = 'manager'
}
node /appserver-wrk/ {
$node_class = 'appserver'
$node_subclass = 'worker'
}
Use the node_class and node_subclass variables in your Hierarchy.
# /etc/puppet/hiera.yaml
---
:backends:
- yaml
:yaml:
:datadir: /etc/puppet/hieradata
:hierarchy:
- "%{::clientcert}"
- "class-%{node_class}-%{node_subclass}"
- "class-%{node_class}"
- common
Now you can define your data right in the YAML for Hiera, instead of params.pp.
# /etc/puppet/hieradata/class-appserver-manager.yaml
servers:
axis2:
subDomain: mgt
carbon:
subDomain: mgt
serverOptions: -Dsetup
server_home: %{carbon_home}
and for the worker:
# /etc/puppet/hieradata/class-appserver-worker.yaml
servers:
axis2:
subDomain: worker
members:
- appserver-mgr2-ip
carbon:
subDomain: worker
serverOptions: -DworkerNode=true
server_home: %{carbon_home}
In your params class, the following then suffices:
$servers = hiera('servers')
Or you don't even bother with the params class, and just replace the uses of the $servers variable with hiera calls. But doing just one call in a params style class is a good practice.
Note: Using the variable value %{carbon_home} from Hiera is somewhat dangerous, you might want to hardcode the actual value in the YAML there.

Rails 4 fomatting with slim error

i have this simple erb code that works perfectly, joint to my i18n.yml file. The idea is to get the client's edit.html.erb page, get the title of that page in my en.yml file and pass that title the #client.fullname variable. Like so:
<h1><%= t('client.edit.title'), :current_client => #client.fullname %></h1>
Now, i'm in the process of translating my erb files into slim. So the result of that line of code is
h1 = t('client.edit.title'), :current_client => #client.fullname
But it wouldnt pass the variable to the en.yml file. Instead, it throws this error:
/app/views/clients/edit.html.slim:1: syntax error, unexpected ',', expecting ')' ...tty2 = (t('client.edit.title'), :current_client => #client.f... ... ^
Would anyone know what i'm doing wrong here?
The hash parameter options should be passed within the method call parentheses, like so
h1 = t('client.edit.title', :current_client => #client.fullname)
Not sure why this would have worked in ERB, but it doesn't look correct as written.
You can also remove the parentheses altogether
h1 = t 'client.edit.title', :current_client => #client.fullname
Please try:
h1
= t('client.edit.title'), :current_client => #client.fullname

How do I access sinatra settings in custom extension specs?

I have an email helper extension I have written for my application. I use settings I have defined on the application like so:
set :mailgun_options, JSON.parse(File.open('config/mailer.json').read)[ENV['RACK_ENV']]
which reads configuration settings from a json file into the global Sinatra settings.
I then have my email helper which references these settings to create connections and what not.
require 'sinatra/base'
require 'faraday'
module Sinatra
module EmailHelper
def connect opts={}
connection = Faraday.new(:url => settings.mailgun_options['mailgun_url']) do |faraday|
if settings.mailgun_options['test']
faraday.adapter :test do |stubs|
stubs.post(settings.mailgun_options['domain'] + '/messages') {[ 200, {}, 'success' ]}
end
else
faraday.request :url_encoded
faraday.adapter Faraday.default_adapter
end
end
connection.basic_auth('api', settings.mailgun_options['key'])
return connection
end
def send_email params={}
connect.post((settings.mailgun_options['domain'] + '/messages'), params)
end
def send_password_reset_email email
template = File.open( File.expand_path( '../../helpers/email_helper/templates/password_reset.erb', __FILE__ ), 'r' ).read
send_email({
:from => 'REscour <noreply#' + settings.mailgun_options['domain'] + '>',
:to => email,
:subject => 'REscour.com Password Reset',
:text => ERB.new(template).result(binding)
})
end
end
end
So, when I am trying to write my specs to test the "connect" method, I get the following error:
undefined local variable or method `settings' for #<Class:0x007faaf9c9bd18>
My spec code is as follows:
module Sinatra
describe EmailHelper
let(:dummy_class) { Class.new { extend EmailHelper } }
it 'should connect to mailgun\'s api' do
app.set :mailgun_options, ::JSON.parse(File.open('config/mailer.json').read)['test']
puts dummy_class.connect
end
end
end
I'm not sure how to interact with the global Sinatra settings from my specs to have the local "settings" variable be defined during execution of the helper code.
I could have the architecture of my application wrong here for all I know. Does anyone have any experience in writing Sinatra extensions using the global settings and write specs for them?
The spec you've written seems to want to be a unit test, because you've not run the extension the way it would be used in an app. In the specs, try something like:
describe "connect" do
let(:app) { Sinatra.new do
helpers Sinatra::EmailHelper
configure do
:mailgun_options, ::JSON.parse(File.open('config/mailer.json')
end
get "/" do
connect
end
end
}
# now write specs for the `connect` helper
end
Using an anonymous class (Sinatra.new do…) lets you quickly set up an app that's convenient for a small test, but there are other ways too.
In the extension, you need to add:
helpers EmailHelper
as per the example in the docs.

Concatenating variable and regexp expression in Puppet

Is it possible at all? My use case is setting wildcard domain's docroot. I have a variable
$docroot = "/var/www"
and, inside apache::vhost {} I'm trying to set
virtual_docroot' => "{$docroot}/%-2+",
That however throws an error saying:
Error: Could not parse for environment production: Syntax error at ' => "$docroot/%-2+",
docroot => $docroot,
serveraliases => ['; expected '}' at /tmp/vagrant-puppet-1/manifests/init.pp:22 on node localhost
My guess is that the whole expression is treated as a regexp, and $ treated as a part of the whole expression. Hence my doubts whether that's possible at all.
The answer turns out to be an orphaned apostrophe, misplaced after virtual_docroot, and copied from puppetlabs-apache documentation, where the faulty code is:
apache::vhost { 'subdomain.loc':
vhost_name => '*',
port => '80',
virtual_docroot' => '/var/www/%-2+',
docroot => '/var/www',
serveraliases => ['*.loc',],
}
Removing the apostrophe fixed the problem. Answer to my question is to set that particular configuration line as:
virtual_docroot => "$docroot/%-2+",
Notice the omitted {} characters.