File traverse and read failure in Vagrant / Puppet setup - vagrant

I have a Vagrant / Puppet set up in which I am attempting to generate a bunch of configuration files and then concatenate them into a master file.
The individual files are generated and written to a conf directory and the last action is to create the master file which uses an erb template to read the files in the conf directory.
<% files = Dir["/etc/sysconfig/iptables/conf/*.conf"] -%>
<% files.each do |name| -%>
<% file = File.open(name) -%>
<% contents = file.read -%>
<%= contents %>
<% end -%>
When I run "vagrant up", everything appears to run correctly but the master configuration file is empty. I have checked the timestamps on the conf directory and the master configuration file and they are correct to (The master config file is created after all the individual config files).
If I ssh into vagrant and run "puppet apply" manually, the master config file is created as expected. I have tried using a bash script instead of the erb method but encountered the same problems.
Does anyone have any ideas what might cause this?

Puppet expands templates at manifest compile time. The content you are trying to catenate is only available at catalog application time.
Have you looked at the concat module? It will likely make short work of your task.

Related

Foreman - replacing repo with local mirrors

We use foreman (v1.14.1) for provisioning and we have a working CentOS 7 installation media for the base OS.
When installing it does install the default repos in /etc/yum.repos.d with online mirrors but I want to replace this with our local mirrors.
I ran accross this workflow (from 2012)
It uses the following snippet to iterate over all the media of the current host os and set write out a repo definition.
<% #host.os.media.each do |media| -%>
[<%= media.name.downcase.strip.gsub(' ', '-').gsub(/[^\w-]/, '') %>]
name=<%= media.name %>
baseurl=<%= #host.os.medium_uri #host, media.path %>
enabled=1
gpgcheck=0
<% end -%>
I have set several Installation media for this OS, each one of them having a specific repo URI (Base, Updates, Plus, Extras...).
The snippet is called in the %post install section of the kickstart but when I want to build the host I get the following error:
Failure parsing Kickstart default: The snippet 'FF_repos' threw an error:
undefined method 'media' for Operatingsystem::Jail (Redhat).
I understand that "#host.os.media.each" is not correct for iterating over the different medias, but how could I do it ?
Any help appreciated :)
Couldn't get this to work so I have simply changed my snippet "FF_repos" to directly bake the repos definition into corresponding repo files on disk.
I added the following in the %post section then to remove default repos and leave our.
rm -f /etc/yum.repos.d/*
<%= snippet("FF_repos") %>

How does Chef include files generated on runtime as a template source

Using Chef recipe, I am first generating a .erb file dynamically based on inputs from a CSV file and then I want to use that .erb file as a template source. But unfortunately the changes made (in .erb file) are not considered while the recipe is converging the resources. I also tried to use lazy evaluation but not able to figure out how to use it for the template source.
Quoting the template documentation:
source Ruby Types: String, Array
The location of a template file. By default, the chef-client looks for
a template file in the /templates directory of a cookbook. When the
local property is set to true, use to specify the path to a template
on the local node. This property may also be used to distribute
specific files to specific platforms. See “File Specificity” below for
more information. Default value: the name of the resource block. See
“Syntax” section above for more information.)
And
local
Ruby Types: TrueClass, FalseClass
Load a template from a local path. By default, the chef-client loads
templates from a cookbook’s /templates directory. When this property
is set to true, use the source property to specify the path to a
template on the local node. Default value: false.
so what you can do is:
# generate the local .erb file let's say source.erb
template "/path/to/file" do
source "/path/to/source.erb"
local true
end
Your question sounds like and XY problem, reading a csv file to make a template sounds counter-productive and could probably be done with attributes and taking advantage of the variable attribute of template resource.
Assuming you know how to capture the values from the CSV file as a local variable in the recipe.
Examples:
csv_hostname
csv_fqdn
Here is what you do to create a template with lazy loading attributes. The following example creates a config file.
example.erb file
# Dynamically generated by awesome Chef so don't alter by hand.
HOSTNAME=<% #host_name %>
FQDN=<% #fqdn %>
recipe.rb file
template 'path\to\example.config' do
source 'example.erb'
variables(
lazy {
:host_name => csv_hostname,
:fqdn => csv_fqdn
})
end
If you need it to run at compile time, add the action to the block.
template 'xxx' do
# blah blah
end.run_action(:create)

Check if a file exists with puppet template

I try to check if a file exists on client who run puppet agent.
On my puppet master, I have a template.erb like this :
<% if File.exists?('/usr/bin/lwp-request') %>SCRIPTWHITELIST="/usr/bin/lwp-request"<% end %>
This little code in my template is needed to my rkhunter module.
The result is always false, however the file exists.
If I add the file on the puppet master, the result is true. So the ruby code seems to be executed on the master.
How can I check on my template if a file exists on client ?
Tested on puppet 2.7.5 and 2.8.1.
Thanks
The only information you have about the node when compiling manifests and templates are Facts that are sent by the node when requesting a catalog.
If you need additional information from the node, then you need to add a Custom Fact that retrieves the information you need (like whether or not a file exists). You can then use the custom fact inside of templates.
Within a Puppet module create a custom fact lib/facter/lwp.rb:
Facter.add(:lwp_request_exists) do
setcode do
File.exists?('/usr/bin/lwp-request')
end
end
then within erb template use something like:
<% if $::lwp_request_exists -%>
some code...
<% end -%>

Chef - Read a file from git repo at runtime and use parse value in recipe

I would like to read a file from a checkout git repository to parse a config file and use this data to perform few resources commands.
git "/var/repository" do
action :sync
end
config = JSON.parse(File.read("/var/repository/config.json" ))
config.each do |job, flags|
#do some resources stuff here
end
This will not work because the file doesn't exist at compile time:
================================================================================
Recipe Compile Error in /var/chef/cache/cookbooks/...
================================================================================
Errno::ENOENT
No such file or directory - /var/repository/config.json
I where trying to load the file in ruby_block and perform the Chef resource actions there, but this didn't worked. Also setting the parsed config to a variable and use it outside of the ruby_block didn't work.
ruby_block "load config" do
block do
config = JSON.parse(File.read("/var/repository/config.json"))
#node["config"] = config doesn't work - node["config"] will not be set
config.each do |job, flags|
#do some stuff - will not work because Chef context is missing
end
end
end
Any idea how I could read the file at runtime and used the parsed values in my recipe?
You may also find it helpful to use lazy evaluation in scenarios like this.
In some cases, the value for an attribute cannot be known until the execution phase of a chef-client run. In this situation, using lazy evaluation of attribute values can be helpful. Instead of an attribute being assigned a value, it may instead be assigned a code block.

Get Current Path of Page in Middleman Layout File

Is it possible to retrieve the current path of a page in a middleman file? For instance, if I have a layout file layout.erb with something like the following:
<%= page.path %>
<%= yield %>
and a test file index.html:
Testing
then when Middleman rendered the page I would get something like:
/index.html
Testing
Middleman also provides the current_page variable. current_page.path is the source path of this resource (relative to the source directory, without template extensions) and current_page.url is the path without the directory index (so foo/index.html becomes just foo).
<%= current_page.path %>
# -> index.html
<%= current_page.url %>
# -> /
Details from Middleman's Middleman::Sitemap::Resource rubydoc.
http://rubydoc.info/github/middleman/middleman/Middleman/Sitemap/Resource
The solution is:
<%= request.path %>

Resources