Best way to write "if condition" within chef template .erb file - ruby

I am using a template node.erb file within Chef.
I have created an if condition within the chef node.erb file but it is not working as expected.
<% if (node['my_port'] > 0) %>
- port:8000
<% end -%>
Within, my chef attributes, I have listed node['my_port'] = 8200
Please suggest what I might be doing wrong.

Related

loop over hash in defined order in ruby template

I have a ruby template (.erb) that I want to iterate over a hash. It should produce the same output file each time the puppet agent runs.
What I currently have is the following. This is my template (part of rsyslog config if anyone is wondering):
<% log_files.each do |log_file, tag| -%>
# <%= log_file %>
$InputFileName <%= log_file %>
$InputFileTag <%= tag %>:
This template is rendered with a hash that looks like this:
log_files => {
'/root/apache_auth.local' => 'httpd',
'/root/install.log' => 'hugo',
},
(Not real logfiles). This works and produces the config file I want. The problem with this is that each time I call the puppet agent, the order of the log files in the hash is changed, so the config file gets rewritten, and subsequently the daemon gets restarted. The functionality stays the same, but I would rather not have the config file rewritten and rsyslog restarted each time the puppet agent runs.
Now I assume that this is unsolvable with hashes, as their nature is that they do not have a defined order. What other options do I have to achieve what I want?
Since the scriptlets inside an ERB template consist of Ruby code, this is essentially a Ruby question. The possible answers therefore depend on which version of Ruby is running underneath your Puppet catalog compiler. However, although there may be better alternatives in newer Ruby, this variation on your code will work in any Ruby supported by Puppet since Puppet 2.7:
<% #log_files.sort.each do |log_file, tag| -%>
# <%= log_file %>
$InputFileName <%= log_file %>
$InputFileTag <%= tag %>:
<% end -%>
The key here (no pun intended) is the sort.

Using Redcarpet Gem with .erb file

I am trying to pull up a markdown file from a database that I created. My server. rb file has the following:
get "/designers/:id" do
id = params[:id]
#content = conn.exec_params("SELECT * FROM articles_info WHERE id = $1",[id]).first
erb :raf
end
In that table is the following markdown information:
# **RAF SIMONS**
*THIS IS THE RAF SIMONS BIO* :blush:
*[Raf Link](http://rafsimons.com/)*
The .erb file works when I have plain text or the following in it:
<%= "#{#content["content"]}" %>
However it only prints the actual .md text as it is. So I have tried using Redcarpet to render the markdown file. The code is as follows in my .erb:
renderer = Redcarpet::Render::HTML.new
markdown = Redcarpet::Markdown.new(renderer)
<%= markdown.render(#content.content) %>
But I am getting the error:
ArgumentError at /designers/1
wrong number of arguments (0 for 1..3)
Which is stemming from the <%= line. I thought at first that the syntax was wrong, so I tried:
markdown.render <%= "#{#content["content"]} %>
However that did not change anything. I also tried adding in a method in the server.rb file, but that gave me more errors. I read through the entire documentation: https://github.com/vmg/redcarpet file but am not understanding where the error is coming from. Is it possible that I need extensions in order to make it work? I also tried:
markdown = Redcarpet::Markdown::new(renderer, extensions={})
But that didn't change anything. Not sure what else to try here! I know that it is tricky but I thought I had a handle on it and have now tried many different iterations and still am having trouble executing it. Any advice would be much appreciated!

Generate a unique erb template for known hosts using the same cookbook - Chef

I have a number of hosts that needs to use different master server hosts and unique ports in a file. So the value of the ports and servers are known.
The end result is that my erb file should produce something of this nature for all the hosts that will run the cookbook:
PG_Host = -h myservername:unique_port
My challenge is how to get the values iterated in the recipe so depending on the short hostname when the server runs the cookbook, it picks up a specific port and a specific master server.
I am having difficulty matching the template with the erb file. I'd like some simple solutions on making this happen. Any pointers will be appreciated.
Here's my recipe:
template '/var/lib/pgsql/conf/mymonitor.sh' do
source 'mymonitor.sh.erb'
owner 'postgres'
action :create
variables(
master_server: 'someserver.fqn',
master_port: '897'
)
end
Template file:
PG_HOST= -h <%= #master_server %>:<%= #master_port %>
So how do I get it to churn out the similar files for anotherserver.fqn on port 5555 etc using some kind of a loop? I'm not sure how my variables for the other servers and their ports should look like.
The variables you pass to the template can be computed during chef-client runs, so in your recipe you can compute the port in the way you wish, and also the server name (master_server) can be calculated during chef-client run, or you can use some of the node's automatic attributes (collected by ohai) such for example node[:hostname] or node[:fqdn]. IE.:
Passing the recipes variables dynamically
server_port = "42#{node[:ipaddress].rpartition('.')[-1]}"
template '/var/lib/pgsql/conf/mymonitor.sh' do
source 'mymonitor.sh.erb'
owner 'postgres'
action :create
variables(
master_server: node[:fqdn],
master_port: server_port
)
end
Or you can use in your template node's attributes directly:
PG_HOST= -h <%= node[:fqdn] %>:<%= node[:mycookbook][:server_port] %>
or using string interpolation
PG_HOST= -h <%= "#{node[:fqdn]}:#{node[:mycookbook][:server_port]"} %>
EDIT:
The value of the attributes can be overridden for each node (or role), so easily you can assign different value for the attributes for each node. Check chef attribute documentation to see details about how attributes work.

Passing binding or arguments to ERB from the command line

I have been playing around with erb from the command line recently. I wanted to make a dirt simple erb template, for example the following:
<%- name = "Joe"; quality = "fantastic" -%>
Hello. My name is <%= name %>. I hope your day is <%= quality %>.
This works if I run
erb -T - thatfile.erb
what I want to do is to make name and quality be passable from command line arguments, so that I could do something like:
./thatfile.erb "Bill" "super"
from the bash prompt and do the same thing.
I am aware that I could write a ruby script that would just read that template in and then use ERB.new(File.read("thatfile.erb")).result(binding), or writing the template after an END and doing likewise, but I'm looking for a more lightweight approach if it exists, because I don't want to write two files for each erb script that I create for this purpose.
Alternatively, you can use a ruby script and load it in as a library.
# vars.rb
#hello = 'kirk'
# template.html.erb
<div><%= #hello %></div>
$ erb -r './vars' template.html.erb
Please note that Ruby 2.2 and newer provide a much nicer solution that was implemented according to this:
erb var1=val1 var2=val2 my-template.erb
I went with the BASH command-line shortcut for environmental variables.
Outside:
STUFF=foo,bar erb input.html.erb >output.html
Inside:
<%
stuff = ENV['STUFF'].split(',')
%>
After a few minutes e-searching I determined the other solutions are all variations on "write the erb wrapper command yourself." Could be wrong, but I ain't going back.
If you are using unix, try following:
$ cat 1.erb
Hello. My name is <%= name %>. I hope your day is <%= quality %>.
$ (echo '<% name="Joe"; quality="fantastic" %>' && cat 1.erb) | erb
Hello. My name is Joe. I hope your day is fantastic.

put Ruby configuration into non-ruby configs

I'd like to be able to have configuration (with the ability to code in Ruby) in one place. Since different configs (like bash scripts) don't understand Ruby, I'd have to prepopulate them. Is there an easy-to-use tool for this?
I've found ruby-parseconfig but that's not what I'm looking for.
Looks like you can do this with chef templates.
Example:
#
# /etc/sudoers
#
# Generated by Chef for <%= node[:fqdn] %>
#
Defaults !lecture,tty_tickets,!fqdn
# User privilege specification
root ALL=(ALL) ALL
<% #sudoers_users.each do |user| -%>
<%= user %> ALL=(ALL) <%= "NOPASSWD:" if #passwordless %>ALL
<% end -%>

Resources