I'm new to Puppet ruby coding and I'm struggling trying to iterate through a hash so I can use both key and value in a .pp file in the module to create directories.
So far, I have two text files that contain the names of the directories to be created and the groups to be used to create them.
name_list.txt
john
mike
tom
group_list.txt
admins
users
tech
Both files are synced, so the first entry in names_list.txt has its counterpart in group_list.txt as the first entry as well. In this way I should be able later to create the following directories with these groups:
john -> admins
mike -> users
tom -> tech
I access those files using two custom facts:
Facter.add('name_list') do
setcode do
if File.exist?("/tmp/name_list.txt")
Array(File.readlines("/tmp/name_list.txt").map{|l| l.chomp})
end
end
end
Facter.add('group_list') do
setcode do
if File.exist?("/tmp/group_list.txt")
Array(File.readlines("/tmp/group_list.txt").map{|l| l.chomp})
end
end
end
and combine them in another custom fact to create the hash:
Facter.add(:hash_list) do
setcode do
hash_list = {}
Facter.value(:name_list).each do |dir_name|
Facter.value(:group_list).each do |group_name|
hash_list[dir_name] = group_name
end
end
hash_list
end
end
Finally, the code part in the manifest .pp file that should create the directories is this one:
$hash_list.each |$dir_name, $new_group| {
file { "/tmp/${dir_name}":
ensure => directory,
owner => 'root',
group => $new_group,
mode => '755',
}
}
When I run puppet agent, I have the below error that shows that the iteration through the group_list is trying to use the last entry in the file only:
Error: Could not find group tech
Info: Unknown failure using insync_values? on type: File[/tmp/john] / property: group to compare values ["tech"] and 0
Error: /Stage[main]/Temp::Test/File[/tmp/john]/group: change from 'root' to 'tech' failed: Could not find group tech
Error: Could not find group tech
Info: Unknown failure using insync_values? on type: File[/tmp/mike] / property: group to compare values ["tech"] and 0
Error: /Stage[main]/Temp::Test/File[/tmp/mike]/group: change from 'root' to 'tech' failed: Could not find group tech
Error: Could not find group tech
Info: Unknown failure using insync_values? on type: File[/tmp/tom] / property: group to compare values ["tech"] and 0
Error: /Stage[main]/Temp::Test/File[/tmp/tom]/group: change from 'root' to 'tech' failed: Could not find group tech
The below shows that indeed the :hash_list hash is not returning the right group for every directory:
# puppet facts hash_list
{
"hash_list": {
"john": "tech",
"mike": "tech",
"tom": "tech"
}
}
I have done lots of tests trying to correct it but I wasn't able to manage it due to my lack of experience in Ruby/Puppet code.
Can someone explain me how to do it properly?
EDIT
After John Bollinger's answer, I saw the need of make my question more clear and remake it. I think that a better approach in my case should be to use a flat file that contains "name,group" like this: (Note: Just to clarify that that file is created and accessed in other server but for testing purposes I'm doing it in the /tmp folder for now and I still need it as the source of that data.)
john,admins
mike,users
tom,tech
and use a custom fact to read those contents so they can be passed to the manifest .pp file I mentioned before and iterate from there.
My problem again is that custom fact. I tried the below but is not giving me the expected result so I would appreciate some help with the correct code:
Facter.add('test') do
setcode do
file_data = {}
if File.exist?("/tmp/new_list.txt")
Array(File.readlines("/tmp/new_list.txt")) do |file|
file.each do |line|
line_data = line.split(',')
file_data[line_data[0]] = line_data[1]
end
end
end
end
end
I was expecting a hash so I could iterate in the manifest as stated earlier but it seems I'm having what looks like an array:
{
"test": [
"john,admins\n",
"mike,users\n",
"tom,tech\n"
]
}
Since this probably is not the best way to do this, I'm open to better solutions so any help would be really appreciated.
I finally found the solution to my question by applying the recommended approach in this comment here: Using Ruby, Reading a file, containing name/value pairs into a hash
It worked like a charm.
Thanks!