Puppet - undefined local variable - puppet

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 %>

Related

Puppet printing undef string instead of nil

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)

Puppet - Set defined types in Nodes.pp

How to overwrite defined type in nodes.pp? I want to able to set custom domain using nodes.pp. Case Default isn't an option.
I'm using puppet 6.0..
The following method doesn't work. It says Could not find declared class resolv::resolv_config.
It looks like it used to work in 3.0 according to this answer.
nodes.pp
node "test001" {
class { 'resolv::resolv_config':
domain => "something.local",
}
}
modules/resolv/manifests/init.pp
class resolv {
case $hostname {
/^[Abc][Xyz]/: {
resolv:resolv_config { 'US':
domain => "mydomain.local",
}
}
}
}
define resolv::resolv_config($domain){
file { '/etc/resolv.conf':
content => template("resolv/resolv.conf.erb"),
}
}
resolv.conf.erb
domain <%= #domain %>
There are a couple of problems here, but the one causing the "could not find declared class" error is that you are using the wrong syntax for declaring a defined type. Your code should be something like this:
node "test001" {
resolv::resolv_config { 'something.local':
domain => "something.local",
}
}
There are examples of declaring defined types in the documentation, https://puppet.com/docs/puppet/latest/lang_defined_types.html.
Once you get that working, you'll find another problem, in that this definition
define resolv::resolv_config($domain){
file { '/etc/resolv.conf':
content => template("resolv/resolv.conf.erb"),
}
}
will cause a error if you try to declare more than one resolv::resolv_config, because they will both try to declare the /etc/resolv.conf file resource. You almost certainly wanted to use a file_line resource.

rspec-puppet: cannot find class that is required

So I have a fully functional 'ldap' class.
Now I want to do some stuff for certain users in my ldap directory.
I do this in a new 'users' module, by first making a new defined_type:
define users::admin (
String $sshkey
) {
file {"/home/${title}":
ensure => directory,
owner => $title,
group => 'root',
require => Class['ldap']
}
...
}
Then I use this defined type in my 'users' module's init.pp:
class users {
users::admin {'ldt':
sshkey => 'mysshkey',
}
}
But when I try to use 'pdk test unit' on this, I get the following error:
failed: rspec: ./spec/classes/users_spec.rb:8: error during compilation:
Could not find resource 'Class[Ldap]' in parameter 'require'
(file: ~/Projects/puppet/modules/users/spec/fixtures/modules/users
/manifests/admin.pp, line: 15) on node <mycomputer>
For completeness's sake, here's my admin_spec.rb (barely changed from the pdk default):
require 'spec_helper'
describe 'users::admin' do
let(:title) { 'namevar' }
let(:params) do
{
'sshkey' => ''
}
end
on_supported_os.each do |os, os_facts|
context "on #{os}" do
let(:facts) { os_facts }
it { is_expected.to compile }
end
end
end
I tried setting my .fixtures.yml as follows, but that didn't help:
fixtures:
symlinks:
ldap: "#{source_dir}"
Any idea on what I'm doing wrong?
EDIT: changed my .fictures.yml to:
fixtures:
symlinks:
ldap: "#{source_dir}/../ldap"
Heck I even manually added a symlink to my ldap module in the spec/fixtures/modules folders. Still the same error.
So it turns out the error had nothing to do with rspec or anything.
I just needed to 'include ldap' in my actual puppet code.

manage hosts file on Windows using Puppet

I'm trying to manage my hosts file on a Windows machine using Puppet and Hiera. My problem is that I have never really used Hiera and I'm struggling with parsing the data content into a proper format.
The relevant section in hieradata/hiera.yaml looks like this:
myhosts : [
'host1 1.2.3.4',
'host2 2.3.4.5',
'host3 3.4.5.6']
I have code that uses a host module, but it also depends on a class that I don't have, so naturally it doesn't work.
class hosts::module (
$myhosts = hiera('myhosts'),
)
{
define update_hosts {
$value = split($name,' ')
host {
"${value[0]}" : ip => "${value[1]}",
}
}
update_hosts { $myhosts :; }
}
I have tried using the file resource instead of the host resource, and also tried doing it without any class, but for some reason I am getting this error
Error: Could not retrieve catalog from remote server: Error 500 on SERVER:
Server Error: Evaluation Error: Error while evaluating a Resource Statement,
Evaluation Error: Error while evaluating a Resource Statement, Duplicate
declaration: File[C:\Temp\tmp.txt] is already declared in file
/etc/puppetlabs/code/environments/production/manifests/site.pp:4; cannot redeclare
at /etc/puppetlabs/code/environments/production/manifests/site.pp:4
at /etc/puppetlabs/code/environments/production/manifests/site.pp:4:1
at /etc/puppetlabs/code/environments/production/manifests/site.pp:10 on node puppet-agent
As you can see, it claims that I have a duplicate declaration, but the weird thing is that it says it has a problem with the same line. It thinks it's declaring the same thing twice for some reason.
This is the code I have now (I know it won't work but the error doesn't really sound related)
define hosts_update($content) {
file { 'C:\Temp\tmp.txt' :
ensure => file,
content => $content,
}
}
hosts_update{ hiera('myhosts'):
content => split($name," "),
}
Any idea how to do this right?
fixed it.
site.pp
include update_hosts
init.pp
class update_hosts::host
(
$hosts = hiera('hosts_list'),
)
{
update_host { $hosts :; }
}
host.pp
define update_host {
​
$value = split($name,' ')
​
host {
"${value[0]}" : ip => "${value[1]}",
target => "C:/Windows/System32/drivers/etc/hosts"
}
}

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