Puppet nested resources create_resources, can't convert string into hash - puppet

trying to build a DNS with this module: ref. But getting this error:
Error: Could not retrieve catalog from remote server: Error 500 on SERVER: Server Error: Evaluation Error: Error while evaluating a Function Call, can't convert String into Hash.
I have nested YAML, but not sure if it's correctly formatted or not or problems with something else within my code.
This is my dns profile dns.pp:
class profile::bind {
validate_hash($conf)
$conf = hiera_hash('bind::zone', undef)
create_resources('profile::bind::make::zone', $conf)
}
This is how I define my zone with make_zone.pp:
define profile::bind::make::zone (
$hash_data,
$zone,
$ensure,
$zone_contact,
$zone_ns,
$zone_serial,
$zone_ttl,
$zone_origin,
) {
validate_hash($hash_data)
bind::zone { $zone :
ensure => $ensure,
zone_contact => $zone_contact,
zone_ns => [$zone_ns],
zone_serial => $zone_serial,
zone_ttl => $zone_ttl,
zone_origin => $zone_origin,
}
}
This is my host1.yaml data:
---
version: 5
bind::zone:
zone: test.ltd
ensure: present
zone_contact: 'contact.test.ltd'
zone_ns:
-'ns0.test.ltd'
-'ns1.test.ltd'
zone_serial: '2018010101'
zone_ttl: '767200'
zone_origin: 'test.ltd'
hash_data:
"newyork":
owner: "11.22.33.44"
"tokyo":
owner: "22.33.44.55"
"london":
owner: "33.44.55.66"
bind::cname:
ensure: present
record_type: master

There are a number of mistakes and misunderstandings in the code. I fixed them up so that the code at least compiles and ended up with this.
Changes to profile::bind:
class profile::bind {
include bind
$conf = lookup('bind::zone')
create_resources(profile::bind::make::zone, $conf)
}
Changes to profile::bind::make::zone:
define profile::bind::make::zone (
Enum['present','absent'] $ensure,
String $zone_contact,
Array[String] $zone_ns,
String $zone_serial,
String $zone_ttl,
String $zone_origin,
Hash[String, Hash[String, String]] $hash_data,
) {
bind::zone { $name:
ensure => $ensure,
zone_contact => $zone_contact,
zone_ns => $zone_ns,
zone_serial => $zone_serial,
zone_ttl => $zone_ttl,
zone_origin => $zone_origin,
}
}
Changes to host1.yaml:
---
bind::zone:
'test.ltd':
ensure: present
zone_contact: 'contact.test.ltd'
zone_ns:
- 'ns0.test.ltd'
- 'ns1.test.ltd'
zone_serial: '2018010101'
zone_ttl: '767200'
zone_origin: 'test.ltd'
hash_data:
"newyork":
owner: "11.22.33.44"
"tokyo":
owner: "22.33.44.55"
"london":
owner: "33.44.55.66"
Some explanation:
immediate problem:
Error: Could not retrieve catalog from remote server: Error 500 on SERVER: Server Error: Evaluation Error: Error while evaluating a Function Call, can't convert String into Hash.
This error was caused because your Hiera data was not correctly structured as a Hash[String, Hash[String, String]]. Notice in the yaml I have removed your key "zone" and created a nested Hash there.
must include the bind class
The camptocamp BIND module requires the bind class to also be declared. See its documentation.
validate_hash function is legacy and in the wrong place
As John Bollinger mentioned in the comment, you had the validate_hash on the wrong line. I think that was a cut/paste issue, because you would have got a different error message if that was really your code. Anyway, since you're using Puppet 5 (I guess that by the version => 5 in your Hiera), don't use the legacy validate functions ; use Puppet's data type validation. So I just deleted that line.
use lookup() instead of hiera_hash()
Again, since you're using Puppet 5, use the lookup() function instead of the deprecated hiera_hash() function.
version 5 belongs in hiera.yaml, not host1.yaml
It won't cause you any problems, but the line version: 5 won't do anything here, and it belongs in your hiera.yaml file. I used a hiera.yaml file as follows for testing:
---
version: 5
defaults:
datadir: data
data_hash: yaml_data
hierarchy:
- name: "Host 1"
paths:
- host1.yaml
zone_ns type confusion
You had 2 problems with the zone_ns - firstly, a typo in your YAML (no space after the -) ; and secondly, you passed in an Array of zone NS's and then tried to coerce the array to an array in your defined type.
zone parameter should be the name var
Notice I had to delete the $zone parameter in your defined type, and I used the special $name variable instead, to get the name from the title.
refactored to use data type validation
Notice how I used Puppet's data type validation on your inputs in the defined type, and then I had no further need for the legacy validate_hash function and other related validate functions. Read more about that here.
I think that's all. Hope that helps!

Related

Iterate over a Puppet Hiera hash in a puppet manifest

Update 1
I've changed the structure of the Hiera data a little and trying a different manifest style.
I'm trying to iterate over the following Hiera hash in a Puppet manifest:
windows-10.yaml:
---
message: "This node is using Windows 10 data"
#profile::hiera_test::backups_enabled: false
profile::hiera_test::firewall:
rule1:
groupName: 'Cortana'
profileNames: ['Private','Public']
action: 'Deny'
rule2:
groupName: 'Microsoft Photos'
profileNames: 'Public'
action: 'Deny'
Although I've updated the data structure and puppet lookup... returns what appears to be valid, I'm not entirely confident in the structure.
I have tried multiple permutations of the manifest. The latest of which looks like the following (based on this answer given by Matt Schuchard):
hiera_test.pp:
class profile::hiera_test (
Hash $data = lookup('profile::hiera_test::firewall', "merge" => 'hash'),
){
$data.each | String $key, Hash $value = {}|{
notify {
default:
name => "Demo_${key}",
message => 'Item DEFAULT',
;
$key:
* => $value,
}
}
}
And the error / output from the above:
PS C:\Users\LocalAdmin> puppet agent -t
Notice: Local environment: 'production' doesn't match server specified node environment 'development', switching agent to 'development'.
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Retrieving locales
Info: Loading facts
Error: Could not retrieve catalog from remote server: Error 500 on SERVER: Server Error: no parameter named 'groupName' (file: /etc/puppetlabs/code/environments/development/site-modules/profile/manifests/hiera_test.pp, line: 31) on Notify[rule1] (file: /etc/puppetlabs/code/environments/development/site-modules/profile/manifests/hiera_test.pp, line: 31) on node winnode1.domain.com
Warning: Not using cache on failed catalog
Error: Could not retrieve catalog; skipping run
Ideally, I want it to work inside a class declaration (why?, because that's about as far as my Puppet learning has got, but happy to further my learning. I'm also using Puppet Enterprise (2019.0.2)).
There are several similar questions around the internet, but they are either out of date (Hiera <5), have incomplete examples including this, or I can't work out how to transpose them into what I need. Apparently create_resources is due for depreciation
?
If anyone can tell me where I'm going wrong that would be great.
I have got a working solution, but hopefully someone can chime in with a better way.
With the example in the question, the line * => $value substitutes * with keys from the Hiera hash. These keys are used as parameters of the notify resource and as per the error, there is no such parameter groupName for notify. I'd either have to change the keys in my Hiera data to match the parameters of notify which wouldn't make much sense or learn how to use the Hiera data keys as parameters...
Anyway, the Hiera data is the same as in the question, but the class is as follows:
class profile::hiera_test (
Hash $data = lookup('profile::hiera_test::firewall', "merge" => 'hash'),
){
$data.each | String $key, Hash $value = {}|{
notify {
default:
name => "Demo_${key}",
message => 'Item DEFAULT',
;
$key:
name => "Demo_${key}",
message => "Output: GroupName: ${value['groupName']}, Profile Names: ${value['profileNames']}, Action: ${value['action']}",
}
}
}
As you can see, I've replaced * with valid parameters of the notify resource.
And the output:
Notice: Output: GroupName: Cortana, Profile Names: [Private, Public], Action: Deny
Notice: Output: GroupName: Microsoft Photos, Profile Names: Public, Action: Deny
Now to replace Notify with the real exec resource. Converting the profileNames array to PowerShell will be fun, I have no doubt.

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"
}
}

Rspec Puppet: Defined Type iteration

Using Puppet 3
Testing using rspec-puppet
Iterating over an array of hashes using a Defined Type
Getting an Error, telling me that my parameter (which defaults to the value of $title) cannot be accessed the way I am because it is not an Array or Hash
I'm using old-style iteration in a puppet module, creating a defined type to iterate over an array of hashes. I'm trying to write a test for this define in rspec-puppet, attempting to assign a hash to the :title using let(). The $title is then supposed to be set to my variable called $daemon, yet my tests keep throwing errors saying that $daemon is not a hash or array.
Here's how I'm creating my defined type:
define my_module::daemon_install ($daemon = $title) {
package {"${daemon['package_name']}":
ensure => "${daemon['package_version']}",
}
file {"${some_fact}/${daemon['binary']}.conf":
ensure => file,
content => "blah"
notify => Service["${daemon['name']}"],
}
service {"${daemon['name']}":
ensure => running,
enable => true,
}
}
And here's how I'm trying to set the title:
describe 'my_module::daemon_install' do
context 'with foo' do
let(:title) {
{
"name" => "foo",
"package_name" => "bar",
"package_version" => "1.0.1",
"binary" => "food",
}
}
# ...
end
end
And here's the error:
daemon is not a hash or array when accessing it with package_version
I'm actually abit new to using defined types for iteration, and very new at rspec-puppet, so I'm not sure if I'm missing something obvious here or not.
But why is it only complaining about package_version and not package_name? And more importantly: why is it not a hash, when (I believe) I'm setting it to a hash correctly in the spec file.
I should mention that another test, of a class which uses this defined type, completes successfully. So it seems related to how I'm trying to set the title when directly testing the define, if I were to guess.
Rspec always converts title into String.
Use $name in define() instead of $title and add the following into tests:
let :title do
{ ... }
end
let :params do
{ :name => title }
end
Please note$name should be equal of $title.

Puppet: configuring with augeas a set of [keys:values] via create_resources from hiera

I am trying to create an interface to pseudo-loop over a set of keys:values from my hiera yaml to update a config file with augeas
define augeas_config (
$key,
$value
)
{
augeas{ "/var/MYCONF/MYCONF.def":
lens => "/var/lib/puppet/lib/augeas/lenses/MYCONF.aug",
incl => "/var/MYCONF/MYCONF.def",
context => "/var/MYCONF/MYCONF.def",
changes => [ "set $key $val" ],
}
}
$augeas_files = hiera_hash('lib_BOX::MYCONF::config', {} )
validate_hash($augeas_files)
create_resources('augeas_config', $augeas_files)
where in my yaml keys:values to be updated are supposed to be in a hash like
lib_BOX::MYCONF::config:
SITE_NAME: "TEST-SITE"
OTHER_STUFF: "DEBUG"
So, the idea is to apply my augeas lense (not sure, if I really need 'context', when 'incl' has to be used with 'lens') for the pairs from my yaml.
However, puppet fails currently complaining about a string instead of an expected hash
Error: Could not retrieve catalog from remote server: Error 400 on SERVER: Evaluation Error: Error while evaluating a Function Call, can't convert String into Hash at /etc/puppet/environments/development/modules/lib_BOX/manifests/config.pp:28:3 on node MY.NODE.FOO
where line 28 is the one with "create_resources('augeas_config'...". Since I get a hash from hiera, I suppose something in my resource definition is broken, but I do not see what??
Maybe somebody has an idea for me?
Cheers and thanks,
Thomas
Data in your yaml file is invalid. Change it to something like:
lib_BOX::MYCONF::config:
first_aug:
key: SITE_NAME
value: "TEST-SITE"
second_aug:
key: OTHER_STUFF
value : "DEBUG"
In addition you do not have to use hiera_hash. You can use just hiera.
Please read about differences between hiera lookup functions and follow examples about lookup types.
Probably you will also have to remove line validate_hash($augeas_files).

Puppet stdlib keys() function syntax error

I'm sure I'm doing something silly, but I can't work out the correct syntax for the stdlib keys() function and can't find any examples on the internet.
Here is what I've tried:
file { ["/tmp/file1", "/tmp/file2"]: # <-- this works as expected
ensure => present,
}
$hash = {"/tmp/file1" => 1, "/tmp/file2" => 2}
file { keys($hash): # <-- syntax error occurs here
ensure => present,
}
It results in this error:
Error: Could not retrieve catalog from remote server: Error 400 on
SERVER: Syntax error at ':'; expected '}' at
/etc/puppet/modules/slony/manifests/master.pp:113 on node slonymaster
What am I missing? I'm using Puppet 3.6.2 with stdlib 4.3.2.
You are just overtaxing your expressions. The idea is sound, but you will have to take an intermediate step.
$filenames = keys($hash)
file { $filenames: ensure => present }
Puppet will only accept literal array values or variables as resource titles.

Resources