hiera dealing with undefined variables in erb templates - puppet

I start using hiera for environment or machine specific variables but I am facing an issue when variable is not found nowhere. Desired behaviour is that shouldn't be included into template.
I did following:
In my manifest code
$yarn_app_mapreduce_am_command_opts=hiera('yarn.app.mapreduce.am.command-opts',undef)
and in erb template I have:
<% if !#yarn_app_mapreduce_am_command_opts.nil? %>
<property>
<name>yarn.app.mapreduce.am.command-opts</name>
<value><%= #yarn_app_mapreduce_am_command_opts %></value>
</property>
<%end %>
According to the documentation here safest is to test on nil. I tried several variants but non of them worked.
Could someone help?

This seems to be an issue with the hiera() function. I checked with the following manifest.
$without_hiera = undef
$with_hiera = hiera('undefined_key', undef)
$no_hiera_template = 'Without Hiera: <% if #without_hiera.nil? %>nil<% else %>not nil: "<%= #without_hiera %>"<% end %>'
$hiera_template = 'With Hiera: <% if #with_hiera.nil? %>nil<% else %>not nil: "<%= #with_hiera %>"<% end %>'
notify {
'hiera':
message => inline_template($hiera_template);
'no_hiera':
message => inline_template($no_hiera_template);
}
This yields:
Notice: Without Hiera: nil
Notice: /Stage[main]/Main/Notify[no_hiera]/message: defined 'message' as 'Without Hiera: nil'
Notice: With Hiera: not nil: ""
Notice: /Stage[main]/Main/Notify[hiera]/message: defined 'message' as 'With Hiera: not nil: ""'
The issue is known and has been discussed at length, but no acceptable fix has come forth yet. The problem is reproducible with the current master and puppet-4 branches.
Seeing as this will be difficult to fix, you are obviously in need of a workaround. The possibilities depend on your data.
If a value of boolean false (note that this is different from the String "false") is not ever sensible for your keys, you can make false the default and just test <% if ! #value -%> in your templates.
If the empty String is not ever a sensible value, you can make that the default, and test for it using <% if ! #value.to_s.empty? -%>
Finally, it might be possible for you to write your own wrapper around the hiera function, which overwrites an arbitrary default such as __KEY_NOT_FOUND__ to nil. Your mileage may vary. See the bug report for some pointers to previous work that may be of help.
It may also be helpful to find out whether one of the related bugs was moved to Jira, and to leave a vote and a note there that this is still an issue with Hiera.

Related

Custom helper with block

I'm using the current release 4.3.3 of Middleman.
I'd like to define a custom helper which accepts a block. For the sake of simplicity, here's a nonsensical example of wrap_me which wraps the block content with the given tag.
It should be possible to implement this with capture_html provided by Padrino (which is explicitly mentioned in the Middleman docs):
module CustomHelpers
def wrap_me(tag, &block)
captured = capture_html(&block)
concat_content "<#{tag}>" + captured + "</#{tag}>"
end
end
Put to use in ERB:
<%= wrap_me('span') do %>
Hello
<% end %>
Now this raises a SyntaxError on line 274 of tilt-2.0.9/lib/tilt/template.rb which tries to eval a string. It appears, the capture is going beyond the "end".
What am I doing wrong here? How to use capture_html and concat_content if Tilt is preventing helpers from having blocks?
Thanks for your help!
(I'll ask the same question in the Middleman forum.)
Apparently, when using blocks, the equal sign has to be dropped. The following works:
<% wrap_me('span') do %>
Hello
<% end %>

Jest - how to test if a component does not exist?

How do I check if a component is not present, i.e. that a specific component has not been rendered?
.contains receives a React Node or array of Nodes as an argument. Instead, use .find:
expect(wrapper.find('selector').exists()).toBeTruthy()
You can use enzymes contains to check if the component was rendered:
expect(component.contains(<ComponentName />)).toBe(false)
If you're using react-testing-library (I know the OP wasn't but I found this question via web search) then this will work:
expect(component.queryByText("Text I care about")).not.toBeInTheDocument();
You can query by Text, Role, and several others. See docs for more info.
Note: queryBy* will return null if it is not found. If you use getBy* then it will error out for elements not found.
Providing a slightly updated answer based on the documentation for enzyme-matchers's toExist. This will require you to install the enzyme-matchers package.
function Fixture() {
return (
<div>
<span className="foo" />
<span className="bar baz" />
</div>
);
}
const wrapper = mount(<Fixture />); // mount/render/shallow when applicable
expect(wrapper.find('span')).toExist();
expect(wrapper.find('ul')).not.toExist();
.contains does not expect a selector, unlike find. You can look at the length attribute of the ShallowWrapper
expect(wrapper.find('...')).toHaveLength(0)
I found I needed to use this syntax with Enzyme and Jest to test if a Connected Component existed in the rendered output.
We use Jest and Enzyme, and I've found the only good test is to import the sub-component and test this way:
expect(component.find(SubComponent).length).toEqual(0); // or (1) for exists, obvs
I tried all the other answers and none worked reliably.
If you are using react-testing-library, then this also will work:
expect(component.queryByText("Text I care about").toBeNull());
expect(within(component).queryByText("Text I care about")).toBeNull();
Note: In my case, I needed to use queryBy* because it doesn´t error out when the text element (that contains the text: Text I care about) does not exist. Therefore, I could evaluate whether there is an existence of a text component or not.

Issue with r.js optimizer and Underscore _.template() function

I have an issue with Underscore (I use an old version [1.3.3] and can't use others for this project) _.template() function after creating optimized build.
After optimizing I have a file with all my initial modules. Underscore (like jQuery) also placed there via shim. Templates files are excluded via onBuildWrite() function and loaded dynamically.
But there is a big problem: after optimization _.template() doesn't work properly. It can't evaluate multiline (but singleline code evaluates fine in some cases [I can't check all of it]) JS in template files. So, for example it can't parse this template file:
<%
var subsIconsNames = {
promosite: 'programs',
photomodel: 'models',
photographer: 'photo',
stylist: 'stylist',
nailmaster: 'nailmaster',
expo: 'exhibition',
tourism: 'turism'
};
%>
<div><%= subsIconsNames [type] %></div>
"Uncaught ReferenceError: subsIconsNames is not defined"
But without optimization it works fine.
Thanks for your attention.

Optional Partials in DustJS

Is it possible to have optional partials in Dust? Let's say I define a layout like this:
<div>
{>"{module}"/>
</div>
I have been defining the module in Express's res.locals object. However, what if I forgot to define a module, or I actually want a default module for use when I do not define one? Worse, what if I did define one but it's the incorrect module, meaning there's no template file in the view folder with the name of that module? I don't want the user to see the ugly error message, which seems to be something like:
Error: ENOENT, open 'view_path\{module}.dust'
where {module} is the name of the module, or an empty string if I did not specify a res.locals.module. Should I resort to try-catch blocks (not even sure how to do them in dust), or is there a method for making templates optional, rather than required? NOTE: The template would be optional, but the module variable would (usually) still be a string. It seems that dust sections are optional, meaning if the exact key is not available, the section is simply not included. For example, say I have the context {friends: [{name: "Harry"}, {name: "Ron"}, {name: "Hermione"}]}. If I define the section:
{#friends}
{name} is {age} years old.
{/friends}
it will output
Harry is years old.
Ron is years old.
Hermione is years old.
Notice there are 2 spaces between is and years in each case, where the age would be if we defined any ages. If this functionality is included, how is it that neither the original creators of dust nor LinkedIn thought to not require partials? How do I specify optional partials in dust?
You could use a conditional like so,
<div>
{?module}
{>"{module}"/>
{:else}
{>"{YourDefaultPartial}"}
{/module}
</div>
This will work when {module} is either undefined or an empty string or a falsey value.
But, in case its a string pointing to a partial that does not exist, it'll throw an error. Hope this helps.

Incorporate jenkins environment variables into groovy template for email notification

I have several environment variables defined for a project on jenkins, amongst which i want to incorporate some onto the email notification sent before and after build success.
But groovy.text.Template does not seem to accept these environment variables.
I have also used "Inject environment variables to the build process Help for feature: Inject environment variables to the build process" and defined my variable as follows
BUILD_NAME=${BUILD_NAME}
where BUILD_NAME is accepted as a parameter while i execute the build.
Please could someone help me on this.
If you are using the email-ext Jenkins plugin to send out emails, there is a "build" object that contains a lot of information about your Jenkins job.
I would do the following:
Print out the properties inside this object by adding the following code to your template:
<% println build.properties.collect{it}.join('<br />') %>
View the email template output. You can either use the Jenkins "Email Template Testing" feature or just run your job. You should see a whole bunch of "KEY=VALUE" print outs.
Look for the environment variable you are interested in. If your environment variable is listed in environment={BUILD_NUMBER=45, BUILD_DISPLAY_NAME=#45...}, you can just call build.environment['BUILD_NUMBER'] to get 45.
If you want to inject custom environment variables I would suggest installing the Env Inject Plugin, defining your variables through that plugin and then looking for the variable in build.envVars
It seems you can try this
template.make(build.environment)
Source
Hopefully I understood your question, but in order to read that parameter in the template you need to call it like this (if BUILD_NAME is a parameter in the jenkins job:
${ENV, var="BUILD_NAME"}
This will return the value of that parameter.
You can do something like this to get it working
<td style="color: #153643; font-family: Arial, sans-serif;font-size: 14px;padding: 20px 0px;" width="60%">
<%= build.envVars['JOB_BASE_NAME'] %>
</td>
build.envVars has all the env variables as a dictionary. Use key value pair to access the variables.
Just do:
<% def env = build.environment %>
<% def name = env.build_name %>
<% if (name != "") { %>
Name: <%=name %>
<% } %>

Resources