puppet 3.8.x variable can't apply to template - puppet

module/bareos_backup_client/manifests/init.pp:
class bareos_backup_client {
##file { "${fqdn}-bareos-client.conf":
mode => 600,
owner => bareos,
group => bareos,
path => "/etc/bareos/director.d/${fqdn}-client.conf",
content => template("bareos_backup_client/bareos-dir-cliententry.erb"),
tag => 'bareos-client',
notify => Service[bareos-dir],
}
}
module/bareos_backup_client/templates/bareos-dir-cliententry.erb:
<% if #clientrunbeforejob -%>
ClientRunBeforeJob = "<%= #clientrunbeforejob %>"
<% end -%>
<% if #clientrunafterjob -%>
ClientRunAfterJob = "<%= #clientrunafterjob %>"
<% end -%>
manifests/nodes/server_1.pp:
include bareos_backup_client
$clientrunbeforejob = "apple"
Why clientrunbeforejob variable can't inject into erb template?

You try and use dynamic scoping. This has not worked in years, and for good reason!
You will likely want to pass this value as a class parameter.
class bareos_backup_client($clientrunbeforejob) {
...
}
Then declare it like
class { 'bareos_backup_client':
clientrunbeforejob => 'apple'
}

Related

Rendering elements classname in client-side without JS framework? (EJS)

Let's say I have an app which shows to the users a list of existing hobbies.
Each hobby has a category, stored in the db.
I want every hobby element to have its background color - dependent on its category.
I want to implement this with appending specific class to each element.
Basic example code:
Server
app.get("/hobbies", (req, res) => {
const hobbies = Hobby.getAllHobbies();
res.render("hobbies", hobbies);
});
Client (EJS)
<% hobbies.forEach(hobby => { %>
<div class=""><%= hobby.name %></div>
<% }); %>
What is the best way to append to each div a class depending of hobby.category?
I know its easily possible in React, but I don't want to use any framework for now.
If your classname is not the same as the category but is based on it, then you just need to pass a lookup object to your template.
Server
const categories_classnames = {
lookup: {
swimming: 'div-swim',
biking: 'div-bike',
painting: 'div-paint',
// ...
}
};
app.get("/hobbies", (req, res) => {
const hobbies = Hobby.getAllHobbies();
// Alternatively, `locals = { ...hobbies, ...categories_classnames }`
const locals = Object.assign({}, hobbies, categories_classnames);
res.render("hobbies", locals);
});
Client
<% hobbies.forEach(hobby => { %>
<div class="<%= lookup[hobby.category] %>"><%= hobby.name %></div>
<% }); %>

Using puppet hash for epp templates

I have next code in erb template:
<% if #proxy_cache_path.is_a?(Hash) -%>
<% #proxy_cache_path.sort_by{|k,v| k}.each do |key,value| -%>
proxy_cache_path <%= key %> keys_zone=<%= value %> levels=<%= #proxy_cache_levels %> max_size=<%= #proxy_cache_max_size %> inactive=<%= #proxy_cache_inactive -%>
<% end -%>
How to porting it for epp template? Im find very low information for it. Please help.
Here's how you can do that:
Showing an example class and how to declare both an ERB and EPP template for comparison:
# manifests/init.pp
class foo () {
$proxy_cache_path = {
'apples' => 1,
'bananas' => 2,
}
$proxy_cache_levels = 2
$proxy_cache_max_size = 2
$proxy_cache_inactive = 2
# Showing use of ERB:
file { '/foo':
ensure => file,
content => template('foo/mytemplate.erb')
}
# Showing use of EPP, which requires an explicit parameters hash:
file { '/bar':
ensure => file,
content => epp('foo/mytemplate.epp', {
'proxy_cache_path' => $proxy_cache_path,
'proxy_cache_levels' => $proxy_cache_levels,
'proxy_cache_max_size' => $proxy_cache_max_size,
'proxy_cache_inactive' => $proxy_cache_inactive,
}),
}
}
Corrected* contents of the ERB file for comparison:
# templates/mytemplate.erb
<% if #proxy_cache_path.is_a?(Hash) -%>
<% #proxy_cache_path.sort_by{|k,v| k}.each do |key,value| -%>
proxy_cache_path <%= key %> keys_zone=<%= value %> levels=<%= #proxy_cache_levels %> max_size=<%= #proxy_cache_max_size %> inactive=<%= #proxy_cache_inactive -%>
<% end -%>
<% end -%>
(*The code in the question is missing the closing end.)
Contents of EPP file:
# templates/mytemplate.epp
<%- | Hash[String, Integer] $proxy_cache_path, Integer $proxy_cache_levels, Integer $proxy_cache_max_size, Integer $proxy_cache_inactive | -%>
<% include stdlib -%>
<% $proxy_cache_path.keys.sort.each |$key| { -%>
proxy_cache_path <%= $key %> keys_zone=<%= $proxy_cache_path[$key] %> levels=<%= $proxy_cache_levels %> max_size=<%= $proxy_cache_max_size %> inactive=<%= $proxy_cache_inactive -%>
<% } -%>
Things to note about the EPP template file content:
1) The parameters and their types are defined on the first line of the template. Use of this line is optional, but good practice.
2) Since we declared the types on the first line, it is unnecessary and redundant to test if $proxy_cache_path is a Hash.
3) We need to include stdlib in order to access the functions keys and sort. This is different to Ruby (ERB) where these methods are built-in to the language.
4) I simplified the code relative to the Ruby (ERB) because Puppet (EPP) has no sort_by function - and actually there was no need to use it in the ERB either, which could be re-written as:
<% if #proxy_cache_path.is_a?(Hash) -%>
<% #proxy_cache_path.sort.each do |key,value| -%>
proxy_cache_path <%= key %> keys_zone=<%= value %> levels=<%= #proxy_cache_levels %> max_size=<%= #proxy_cache_max_size %> inactive=<%= #proxy_cache_inactive -%>
<% end -%>
<% end -%>
Finally some tests:
# spec/classes/test_spec.rb:
require 'spec_helper'
describe 'foo', :type => :class do
it 'content in foo should be the same as in bar' do
foo = catalogue.resource('file', '/foo').send(:parameters)[:content]
bar = catalogue.resource('file', '/bar').send(:parameters)[:content]
expect(foo).to eq bar
end
end
And the tests pass.
See docs here.

How to pass custom variable to partial in hexo?

I want to create an alternating layout using the static site generator hexo – the text of every second post on an overview page should be on the right.
The partial I’m using needs to pass on a custom variable like textOrientation = "left" to the partial function.
<%site.tags.findOne({name: 'featured'}).posts.sort('date', -1).limit(5).each(function(post, index) {%>
<%- partial('_partial/project-excerpt', {item: post}) %>
<% })%>
The template project_excerp.ejs then needs to generate the according classes bases on the passed variable.
My template (project_excerp.ejs):
<a class="???" href="/project/<%= item.slug %>"><%= item.title %></a>
So the questions are:
How can I extend the post variable with my own variable textOrientation and
How can I use an if then else in my project_excerp.ejs-template?
Okay, found a solution myself.
index.js:
<%site.tags.findOne({name: 'featured'}).posts.sort('date', -1).limit(5).each(function(post, index) {%>
<% if(index % 2 === 0) { %>
<% post.textOrientation = "left"; %>
<% } else { %>
<% post.textOrientation = "right"; %>
<% } %>
<%- partial('_partial/project-excerpt', {item: post}) %>
project_excerp.ejs:
<% var projectInfoClass = "ta-right"; %>
<% if(item.textOrientation === "right") {%>
<% projectInfoClass = "ta-left"; %>
<% } %>
<a class="<%= projectInfoClass %>" href="/project/<%= item.slug %>"><%= item.title %></a>
Also helpful to read the EJS-docs.

Does EJS handle array.map(callback)?

I am passing an array of objects to an EJS template, which I would like to map into links using the regular .map() method of arrays. But for reasons I can't figure out, the callback I'm passing to map() doesn't work within EJS the way I'd expect, and I'm getting empty results.
My data is an array of objects, each with a "section" and a "name" key. This array is passed as "entries" to the template:
siteHeaders = [ { section: "home", name: "Home"},
{ section: "about", name: "About Me"},
... plus few more ]
The template looks like this, and I have it in a local variable called (surprise) template:
<% entries = entries.map(function(elem) { -%>
<% return -%>
<a href="/<%= elem.section %>">
<%= elem.name %>
</a>
<% } ) -%>
<p><%- entries.join(" | ") %></p>
The result of this template, when I call require('ejs').render(template, {entries: siteHeaders}) is:
<p> | | | | </p>
What I don't get is why this doesn't work in an EJS template, when the corresponding map call works just fine in REPL:
> siteHeaders.map(function(e){ return '' + e.name + '' })
[ 'Home',
'About Me',
'Portfolio',
'Blog',
'Contact' ]
>
Any clues?
This code should work:
<% entries = entries.map(function(elem) {
return '' + elem.name + '';
}) -%>
<p><%- entries.join(" | ") %></p>
You can't use simple html inside of functions. It's possible only in loops and conditions.
It's not as clean as join(' | '), but if you don't want to concatenate, you can do this:
<% entries.forEach(function(entry, i, entries){ %>
<%= entry.name %>
<%= i == entries.length-1 ? ' | ' : '' %>
<% } %>
I didn't manage to use map in EJS, but I found a way that at least for me is easy too
<ul>
<% for (item of toDoList) { %>
<li> <%= item %> </li>
<% } %>
</ul>

How to print a variable directly using EJS template engine?

I'm using Node.js with Express web framework (and EJS template engine).
When I have to print a variable I do something like:
<% if (value) { %>
<%= value %>
<% } %>
Can I do the same thing without open others brackets ? Like:
<% if (value) { PRINT VALUE } %>
Is this possible? How to print the variable?
I'm amazed to find that apparrently you can't do it, like in PHP:
<?php if ($value) : ?>
<?php echo $value; ?>
<?php endif; ?>
However a slightly better solution may be to do
<%= (value) ? value : '' %>
I say this assuming that the condition may occasionally be more complex, i.e.
<%= (str.length > 100) ? truncate(str) : str; %>
Which is much nicer than
<% if (str.length > 100) { %>
<%= truncate(str) %>
<% } %>
even if it is a slightly contrived example.
I'd love to be shown a direct command to do it, as per your original question.
There is now an outputFunctionName parameter that you can use. According to the documentation:
outputFunctionName Set to a string (e.g., 'echo' or 'print') for a function to print output inside scriptlet tags.
<% console.log(posts) %>
NB: Make sure you define your variable in any other file you have eg app.js file...
let posts = [];
app.get("/", (req, res) => {
res.render("home", {
posts: posts
});
});

Resources