Helm template check if boolean value is actually empty not false - kubernetes

How to tell if a value, more specifically a a boolean typed value is empty in gotpl alias helm template?
How to tell if a simple value is empty?

You have multiple options, how to tell if a normal (not boolean) value is empty.
A very brute force and quite long way is to put an if statement around your node such as
{{ if .Values.simpleText }}
isEmpty: false
{{ end }}
This will evaulate isEmpty as false only if there is any value inside .Values.simpleText
A better way to do this is to use the inbuilt empty function:
isEmpty2: {{ empty .Values.simpleText }}
This does the same as the first example just shorter and arguably more
readable
The issue with theese methods is that if you have a node which is a bool theese methods wont work.
#values.yaml
myBool: false
#-----------------------------------------
#template.yaml
isBoolEmpty: {{ empty .Values.myBool }}
#-----------------------------------------
#output
isBoolEmpty: true
This will claim that .Values.myBool is empty even tho it clearly has
a value which is false.
Now there is an option to check if a value is nil
isNil: {{ eq nil .Values.nilValue }}
This will result as true if the value is indeed nil ( nilValue: ) but as soon as you have a value inside nilValue you will get a type exception.
The solution that I found and seemed the easiest to understand and to use is:
{{ if (quote .Values.myBool | empty) }}
isActuallyEmpty: ".Values.myBool is empty"
{{ else }}
isActuallyEmpty: ".Values.myBool has a false or true value"
{{ end }}
I am sorry if this is very trivial but I know that I was struggleing with this question for some time.

Related

How to check whether hash has a value for the key in puppet

I have a hash defined as below:
Hash[String, String] $hashtest = { "abc" => "test1", "xyz" => "test2" },
I have String variable, I need to search for the given key in the hash and if a value is found, I need to assign that value to the variable "result" otherwise I need to assign a default value "test". How can I do this is in puppet? Or only way to do this is using if else condition?
It should be similar like this, but the below code is not working. Kindly correct me what I'm doing wrong.
String $variable = $hashtest[$key] ? { true => $hashtest[$key], false => "test" },
It would be really helpful if someone helps me with this thanks in advance.
I am assuming in your pseudocode you are intending to assign a value with a return from a selector, and not also providing a pseudocode for a ternary-like expression in Puppet. With that in mind, we can achieve this with something similar to Python:
String $variable = $key in $hashtest ? {
true => $hashtest[$key]
false => "test"
}
Note that prior to Puppet 4 you would need the has_key? function (analogous to has_key Hash method in Ruby) from stdlib:
String $variable = has_key($hashtest, $key) ? {
true => $hashtest[$key]
false => 'test'
}
In stdlib there is also a function roughly equivalent to a "null coalescing" operator in other languages (null being roughly equivalent to undef type in Puppet and nil in Ruby) that would provide a cleaner expression:
String $variable = pick($hashtest[$key], 'test')
Similar to the coalescing patterns in other languages, pick will return the first argument that is not undef or empty.
As well as matts answer you can also use the following
$variable = $hashtest[$key].lest || { 'test' }
$variable = ($key in $hashtest).bool2str($hashtest[$key], 'test')
$variable = $hashtest.has_key($key).bool2str($hashtest[$key], 'test')
All of these options are missing the most simple and powerful option that's been available from the core library since puppet 6; the get function.
The get function allows you specify a dot separated path of nested keys to look up as the first argument, and a default value for the second. By default, it will return undef if a value cannot be found, making it ideal for use in conditional expressions since undef is the only value in puppet that automatically converts to false. You can even pass a lambda to it to handle missing values.
In your case, the answer is as simple as $variable = $hashtest.get($key, 'test') or $variable = get($hashtest, $key, 'test'), though I personally find the first option easier to read.

unable to pass dict into tpl function (actually anything but <dot>')

I'm new to helm/go templating, and it seems that I still don't understand how context work. Can someone explain, where is problem and why dict cannot be used like this?
I have this template in file stubs/.test.yaml (which I'd like to use with tpl function):
test: abc
test2: {{.Values.key}}
in values.yaml there is just:
key: value
and I include this template like this:
{{ tpl (.Files.Get "stubs/.test.yaml" ) (.) }}
produces:
test: abc
test2: value
So I loaded file from stubs/.test.yaml, and passed it current (root) context, and .Values.key was found and substituted. As expected.
Now lets redefine stubs/.test.yaml as:
test: abc
test2: {{.key}}
and pass a dict as a context when substituting template, as:
{{ tpl (.Files.Get "stubs/.test.yaml" ) (dict "key" .Values.key) }}
so I'd expect the same result, since I passed dict in place of root context, dict has single value named key, with value taken from .Values.key, which is correctly referenced in that template. But I got:
error calling tpl: cannot retrieve Template.Basepath from values inside tpl function: test: abc
test2: {{.key}}: "BasePath" is not a value
instead. What is happening here?
EDIT: I was testing it more, and it's not about dict. I have to pass . as second parameter into tpl function, otherwise it fails.
Version 3.10
I think I found answer in this issue
IIUC: before tpl starts, it creates object .Template (see builtin_objects) in root context, where there are data about currently processed template. So if you are using tpl you must not change context and pass ., or you must pass something as context, from what is valid $.Template accessible.
So if we're passing dict as in example in my question:
{{ tpl (.Files.Get "stubs/.test.yaml" ) (dict "key" .Values.key) }}
it will not work. But if you extend dict definition like this:
{{ tpl (.Files.Get "stubs/.test.yaml" ) (dict "key" .Values.key "Template" $.Template) }}
it will work now.

Helm using ternary with condition checking if list is empty

I am using ternary operand to set values to a variable in my helm template. I am unable to get the condition to check if a list is defined.
{{- $environment_names:= ternary $service.environments $.Values.default.environment_names $service.environments }}
executing "root-app/templates/applications.yaml" at <$service.environments>: wrong type for value; expected bool; got interface {}
is there a possibility to convert this map to boolean? I tried bool and lengthwhich are not functions in helm.
It seems like you can use the default template function here: if $service.environments is defined, use its value, but if not (if it's zero, nil, empty string, or otherwise "falsey") use the default value.
{{- $environment_names := $service.environments | default $.Values.default.environment_names }}
I figured out how I could make it working
{{- $environment_names:= ternary $service.environments $.Values.default.environment_names (hasKey $service "environments") }}

jinja2: passing a string as a parameter to a macro?

I have the following python code to invoke jinja2. In this code, I want to pass a string as an argument to a macro ...
#!/usr/local/bin/python3
import jinja2
test_template = '''
{% macro testmacro(start, arg1, arg2, arg3) -%}
start_{{arg1}}_{{arg2}}_{{arg3}}
{%- endmacro %}
result = {{ testmacro('begin', A, B, C) }}
'''
template = jinja2.Template(test_template)
rendered = template.render(dict(A='AAA', B='BBB', C='CCC'))
print(rendered)
The result is start_AAA_BBB_CCC. However, I want it to be begin_AAA_BBB_CCC.
And if I call the macro with 'xyz' as its first parameter, then I want the output to be xyz_AAA_BBB_CCC.
I don't want the first parameter to be passed to jinja2 from the caller as another variable. I want it hard-coded inside of the template, itself, as a parameter to the macro call.
How can I do this in jinja2 ?
Thank you very much in advance.
Oh, never mind. The answer is simple:
{% macro testmacro(start, arg1, arg2, arg3) -%}
{{start}}_{{arg1}}_{{arg2}}_{{arg3}}
{%- endmacro %}
I thought I tried that before, and it didn't work, but I must have made some other error that I didn't realize.
As long as the string argument is passed within quotes, this works.

Pyrocms tag as parameter in another tag

I tried to use {{ page:slug }} as a parameter in my page to get the blog articles from the category of the same name. For example:
Pagename = About me
Slug = about-me
Then create a category with the same name and slugname in Blog with associated articles. Now in pagelayouts I thought I could create the following, but it doesn't seem to work. Does anyone know why not?
{{ blog:posts order-by="created_on" dir="asc" category="{{ page:slug }}" }}
<section class="title">
<h4>
{{ title }}
</h4>
</section>
<section class="item">
<p>{{ intro }}</p>
<p>Read more..</p>
</section>
{{ /blog:posts }}
Solved
I found the answer by asking it face to face to another developer. Since this is a templating language, it doesn't support functionality. It just reads pre-made variables. So I will have to solve this problem by creating another method in pages/plugins.php.
You don't need to try and embed a tag in a string, just pass the tag straight to the attribute.
{{ blog:posts order-by="created_on" dir="asc" category="{{ page:slug }}" }}
Should be:
{{ blog:posts order-by="created_on" dir="asc" category=page:slug }}
Easier than you thought ey?
This is how I solved it using PHP. The below edit checks if the page parameter from the {{ blog:posts }} tag is set. When it is, it grabs the last segment and uses it as category filter in the database query to retreive only those posts:
In system/cms/modules/blog/plugin.php look for the 'posts' function and add a parameter:
$page = $this->attribute('page');
Then use the following statement to check if the parameter has been set and then add a 'where' statement:
if($page) //check if page is set
{
$segment = end($this->uri->segment_array()); //get the last segment from the url
$this->db->where('blog_categories.slug', $segment); //use the segment as filter
}
Now you can create a page containing blog posts from which the categories refer to its pagename like for example: www.website.com/pagename/subpagename/subsubpagename/awesome then use this as pagelayout and it will load a list of blogposts that have 'awesome' as category:
<h3>{{ page:title }}</h3>
{{ blog:posts order-by="created_on" dir="asc" page="true" }}
<h4>{{ title }}</h4>
<p>
{{ intro }}</p>
<p>
Read more..</p>
{{ /blog:posts }}
Instead of using tags i have found a simple solution to avoid tags as much as we can. Here is it.
Instead of using tags call a view in plugin and pass the third parameter as TRUE so that it return string instead of loading view than do any kind of looping and conditional checking in the view as usuall as you do with php o course. No need to meet tags there. After that in plugin where you are calling this view simply return a single variable and use your variable in tags in the page to display content of view.
Here is an example
class Plugin_Home extends Plugin
{
function test()
{
$this->load->model('test/test_m');
$data['test'] = $this->test_m->index();
return $this->load->view('test/test_view',$data , TRUE);
}
}
And in the page you can call it like this
{{ Home:test }}
And get rid of tags for conditioning and looping