Puppet printing undef string instead of nil - puppet

I'm currently in the process of updating some legacy Puppet files to a newer version of puppet and am running into the following problem:
The hieradata for one of our server has variables that can be left undefined and still work when we generate an env.yml for our RoR application from an erb file.
Previously, this worked correctly with our env.yml generating those values like:
read_only_mode:
With our update to Puppet v5, the values now generate as:
read_only_mode: undef
In the erb template:
read_only_mode: <%= #data['read_only_mode'] %>
I'm currently trying to write a test in the Puppet file that generates the env.yml with the thought that the following logic should work:
for ($key, value in $hieradata) {
if ($hierdata[$key] == undef) {
$hieradata[$key] = '' // Empty string
}
}
As implemented:
$envdata.each |String $key, String $value| {
if $envdata[$key] == undef {
$envdata[$key] = ''
}
}
However, this isn't working and the undef string is still being printed.
Does anyone have ideas as to a solution to this issue?

This
read_only_mode: undef
is going to be interpreted as a string and it's going to be passed into the template as a string, remembering that an ERB is Embedded RuBy we have to pass in something that Ruby is going to recognise as a null value and you can do this as follows.
read_only_mode: null
read_only_mode: Null
read_only_mode: NULL
read_only_mode: ~
read_only_mode:
So I'm not sure why you needed to change from
read_only_mode:
to
read_only_mode: undef
unless there is something else going on in your code, I couldn't really tell as your problem statement seemed to be missing a few bits.
Once I had my values set in hiera as above I'd then wrap the template code in an if;
# erb template
<% if #data != nil -%>
value2 <%= #data %>
<% end -%>
The class
# pp class file
$data = lookup(read_only_mode)
file { '/tmp/test':
ensure => file,
content => template('module2/test.erb'),
}
If you're refactoring your template for Puppet 5 you might want to go the whole hogg and convert it to epp which is much easier to use and you get access to regular Puppet language functions such as each.

We ended up changing the Hash values using the following code:
$data_tuples = $data.map |$key, $value| {
if type($value) == Undef {
[$key, '']
} else {
[$key, $value]
}
}
$data_filtered = Hash($data_tuples)

Related

Puppet - undefined local variable

I'm getting undefined error but it is defined already. I'm sure this was working before (maybe in puppet 3) but I'm trying to use that code on puppet 6 (on a new server).
Any idea what is the issue? Here is the error code:
Error: Error while evaluating a Function Call, Failed to parse template resolv/resolv.conf.erb:\n
Filepath: /etc/puppetlabs/puppet/modules/resolv/templates/resolv.conf.erb\n Line: 1\n
Detail: undefined local variable or method `domain' for #<Puppet::Parser::TemplateWrapper:0x60d6ba83>\n
Here is the code:
class resolv {
case $hostname {
/^[Abc]/: {
resolv:resolv_config { 'Default':
domain => "mydomain.local",
}
}
}
}
define resolv::resolv_config($domain){
file { '/etc/resolv.conf':
content => template("resolv/resolv.conf.erb"),
}
}
Here is the template content:
cat resolv.conf.erb
domain <%= domain %>
Figured it out.
All Puppet variables need to be prefixed with # in Puppet 4+
So resolv.conf.erb should look like
domain <%= #domain %>

freeradius unlang disable escaping

I have the following list of VLAN's I want to check against ldap.
Tmp-String-0 = "CN=vlan10,CN=Users,DC=aaa,DC=local;CN=vlan20,CN=Users,DC=aaa,DC=local"
With ulang I explode them and loop through them
if ("%{explode:&control:Tmp-String-0 ;}" > 0) {
foreach &control:Tmp-String-0 {
Then I try to do checking with
Tmp-String-1 := "%{ldap_aaa.local:ldapi://192.168.0.199:389/cn=Users,dc=aaa,dc=local?memberof?sub?(&(objectCategory=User)(sAMAccountName=%{%{Stripped-User-Name}:-%{User-Name}})(memberOf=%{Foreach-Variable-0}))}"
However %{Foreach-Variable-0} gets the escaped version of the string:
CN3dvlan202cCN3dUsers2cDC3daaa2cDC3dlocal
The escaped version is not working, if I replace it with hardcoded unescaped version the it works.
CN=vlan20,CN=Users,DC=aaa,DC=local
How to prevent unlang for escaping the variable?
You can't prevent unescaping in v3. In version 4 there's the concept of "tainted" and "untainted" values, with tainted values being escaped, and "untainted" values being inserted verbatim, but I'm not sure that's implemented yet in the LDAP module expansions.
You could use the group membership checks in the LDAP module to do what you're trying to implement with the xlat expansion?
e.g.
if ("%{explode:&control:Tmp-String-0 ;}" > 0) {
foreach &control:Tmp-String-0 {
if (LDAP-Group == "%{control:Tmp-String-0}") {
update reply {
# VLAN-Attrs
}
}
}
}

puppet and inline_epp and using hiera deliver content

It's possible to use inline_epp's using string variable like this ?
"htaccess": {
"content": [
"<% include stdlib -%>",
"AuthType Basic ",
"AuthUserFile <%= $auth_file %>",
"Require valid-use"
],
"params": {
"auth_name": "Bootstrap content for provisioning",
"auth_file": "file_path"
}
}
and (some.pp):
$htacces = $sub_attrs['htaccess']
$content = $htacces['content']
$data = join($content, "\n")
$auth_file = "sgsdgsdfgsdfg"
notice inline_epp($data)
This is result in the notice line : Invalid EPP: This Name has no
effect. A value was produced and then forgotten (one or more preceding
expressions may have the wrong form)
Idea is use hiera data to deliver content to epp .
Using puppet 5.5.2 and Ubuntu 16.04
There looks like there are a few things going on here.
For one thing, is the syntax of that notice function correct? The Puppet Cookbook shows notice with either brackets notice("message") or in Puppet's class syntax notify { "message": }).
Also, inline_epp takes a hash of the parameters used to fill in the EPP. See the Puppet documentation on inline_epp. In your case, that'd be something like inline_epp($data, { auth_file => $auth_file }).
And lastly, EPP needs a line at the top listing its parameters. In your case it should be something like <%- | String $auth_file | -%>. See the Puppet documentation on EPP files.

Twig_Template::getSource() doesn't work until the template has been cached

I need to load and show a Twig template's source.
The template's getSource() method appears to work by using reflection to find its own class file, and reading the comment block at the end of it (which has the Twig code).
public function getSource()
{
$reflector = new ReflectionClass($this);
$file = $reflector->getFileName();
// ...
}
Unfortunately, that file is only available when the template is loaded from the file cache - before then, the class is defined at runtime and the ReflectionClass will return Environment.php(403) : eval()'d code as the class file.
if (!class_exists($cls, false)) {
$content = $this->compileSource($this->getLoader()->getSource($name), $name);
if ($this->bcWriteCacheFile) {
$this->writeCacheFile($key, $content);
} else {
$this->cache->write($key, $content);
}
eval('?>'.$content);
}
Is there any other way I can get the source from Twig, or is it only possible if I find and read the original .html.twig file directly?
Oops. The answer was right there in the code, of course:
$content = $this->compileSource($this->getLoader()->getSource($name), $name);
All I needed was to replace $environment->loadTemplate($name)->getSource() with $environment->getLoader()->getSource($name).

Puppet: unable to get hiera variable

I've been using hiera for several weeks now and all was working fine til few days ago when i started to get that kind of message:
Error: Could not retrieve catalog from remote server: Error 400 on SERVER: Could not find data item nom in any Hiera data file and no default supplied on node d0puppetclient.victor-buck.com
Warning: Not using cache on failed catalog
Error: Could not retrieve catalog; skipping run
So i tried to make a very simple test to check if the problem came from my last code changes and i'm still getting this message. I can't get hiera variable anymore.
Below the test i made:
hiera.yaml:
---
:backends:
- yaml
:yaml:
:datadir: /etc/puppet/hieradata
:hierarchy:
- common
site.pp:
# /etc/puppet/manifests/site.pp
case $operatingsystem {
'Solaris': { include role::solaris }
'RedHat', 'CentOS': { include redhat::roles::common }
/^(Debian|Ubuntu)$/: { include role::debian }
# default: { include role::generic }
}
case $hostname {
/^d0puppetclient/: { include test }
}
test.pp:
class test{
$nom = hiera('nom')
file {"/root/test.txt":
ensure => file,
source => "/etc/puppet/test.txt.erb",
}
}
test.txt.erb:
<%= nom %>
Any idea about to fix this? I thought this could be an file access right issue, so i tried to grante access on some files (755) and it's not working...
You need to define nom in your common.yaml in order for it to hold a value. You can set a default value and conditionally create the file if you don't plan on setting it.
class test {
$nom = hiera('nom', false)
if $nom {
file { '/root/test.txt':
ensure => file,
content => template('test/test.txt.erb')
}
}
}
Notice how i used content instead of source. When using erb templates you need to specify the content using the template() function.
Using Templates
If you use source it is expecting a file rather than an erb template.
Hope this helps.

Resources